blob: 6b0baa42cfa22e8776b2f55991abb5fa50a42930 [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"
Robert Phillips375e1f62020-10-23 16:13:57 -040011#include "include/private/SkMalloc.h"
Robert Phillips3ac83b2f2020-10-26 13:50:57 -040012#include "include/utils/SkRandom.h"
Brian Salomon8f7d9532020-12-23 09:16:59 -050013#include "src/core/SkCanvasPriv.h"
Robert Phillips83c38a82020-10-28 14:57:53 -040014#include "src/core/SkMessageBus.h"
Robert Phillips375e1f62020-10-23 16:13:57 -040015#include "src/gpu/GrDefaultGeoProcFactory.h"
Adlai Hollera0693042020-10-14 11:23:11 -040016#include "src/gpu/GrDirectContextPriv.h"
Robert Phillips375e1f62020-10-23 16:13:57 -040017#include "src/gpu/GrGpu.h"
18#include "src/gpu/GrMemoryPool.h"
19#include "src/gpu/GrOpFlushState.h"
Robert Phillips26f3aeb2020-09-16 10:57:32 -040020#include "src/gpu/GrProxyProvider.h"
21#include "src/gpu/GrRecordingContextPriv.h"
Robert Phillips1a82a4e2021-07-01 10:27:44 -040022#include "src/gpu/GrResourceProvider.h"
Robert Phillips3380be92020-09-25 12:47:10 -040023#include "src/gpu/GrStyle.h"
Robert Phillipsd464feb2020-10-08 11:00:02 -040024#include "src/gpu/GrThreadSafeCache.h"
Robert Phillips4dca8312021-07-28 15:13:20 -040025#include "src/gpu/v1/SurfaceDrawContext_v1.h"
Robert Phillips26f3aeb2020-09-16 10:57:32 -040026#include "tests/Test.h"
27#include "tests/TestUtils.h"
Robert Phillips375e1f62020-10-23 16:13:57 -040028#include "tools/gpu/ProxyUtils.h"
Robert Phillips26f3aeb2020-09-16 10:57:32 -040029
Robert Phillipsc2fe1642020-09-22 17:34:51 -040030#include <thread>
31
Robert Phillips26f3aeb2020-09-16 10:57:32 -040032static constexpr int kImageWH = 32;
33static constexpr auto kImageOrigin = kBottomLeft_GrSurfaceOrigin;
Robert Phillips6e17ffe2020-10-06 14:52:11 -040034static constexpr int kNoID = -1;
Robert Phillips26f3aeb2020-09-16 10:57:32 -040035
36static SkImageInfo default_ii(int wh) {
37 return SkImageInfo::Make(wh, wh, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
38}
39
Robert Phillips4dca8312021-07-28 15:13:20 -040040static std::unique_ptr<skgpu::v1::SurfaceDrawContext> new_SDC(GrRecordingContext* rContext,
41 int wh) {
42 return skgpu::v1::SurfaceDrawContext::Make(rContext,
43 GrColorType::kRGBA_8888,
44 nullptr,
45 SkBackingFit::kExact,
46 {wh, wh},
47 SkSurfaceProps(),
48 1,
49 GrMipMapped::kNo,
50 GrProtected::kNo,
51 kImageOrigin,
52 SkBudgeted::kYes);
Robert Phillips3380be92020-09-25 12:47:10 -040053}
54
Robert Phillips375e1f62020-10-23 16:13:57 -040055static void create_view_key(GrUniqueKey* key, int wh, int id) {
56 static const GrUniqueKey::Domain kViewDomain = GrUniqueKey::GenerateDomain();
57 GrUniqueKey::Builder builder(key, kViewDomain, 1);
Robert Phillips26f3aeb2020-09-16 10:57:32 -040058 builder[0] = wh;
59 builder.finish();
Robert Phillips6e17ffe2020-10-06 14:52:11 -040060
61 if (id != kNoID) {
62 key->setCustomData(SkData::MakeWithCopy(&id, sizeof(id)));
63 }
Robert Phillips375e1f62020-10-23 16:13:57 -040064}
Robert Phillips26f3aeb2020-09-16 10:57:32 -040065
Robert Phillips375e1f62020-10-23 16:13:57 -040066static void create_vert_key(GrUniqueKey* key, int wh, int id) {
67 static const GrUniqueKey::Domain kVertDomain = GrUniqueKey::GenerateDomain();
68 GrUniqueKey::Builder builder(key, kVertDomain, 1);
69 builder[0] = wh;
70 builder.finish();
71
72 if (id != kNoID) {
73 key->setCustomData(SkData::MakeWithCopy(&id, sizeof(id)));
74 }
75}
76
Robert Phillips67e58cb2020-11-02 08:57:39 -050077static bool default_is_newer_better(SkData* incumbent, SkData* challenger) {
78 return false;
79}
80
Robert Phillips375e1f62020-10-23 16:13:57 -040081// When testing views we create a bitmap that covers the entire screen and has an inset blue rect
82// atop a field of white.
83// When testing verts we clear the background to white and simply draw an inset blur rect.
Robert Phillips3380be92020-09-25 12:47:10 -040084static SkBitmap create_bitmap(int wh) {
Robert Phillips26f3aeb2020-09-16 10:57:32 -040085 SkBitmap bitmap;
86
87 bitmap.allocPixels(default_ii(wh));
88
89 SkCanvas tmp(bitmap);
90 tmp.clear(SK_ColorWHITE);
91
92 SkPaint blue;
93 blue.setColor(SK_ColorBLUE);
Robert Phillips3380be92020-09-25 12:47:10 -040094 blue.setAntiAlias(false);
Robert Phillips26f3aeb2020-09-16 10:57:32 -040095
Robert Phillips3380be92020-09-25 12:47:10 -040096 tmp.drawRect({10, 10, wh-10.0f, wh-10.0f}, blue);
Robert Phillips26f3aeb2020-09-16 10:57:32 -040097
Robert Phillipsdefd2232020-09-25 15:25:46 -040098 bitmap.setImmutable();
Robert Phillips26f3aeb2020-09-16 10:57:32 -040099 return bitmap;
100}
101
Robert Phillips67e58cb2020-11-02 08:57:39 -0500102class GrThreadSafeVertexTestOp;
103
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400104class TestHelper {
105public:
106 struct Stats {
107 int fCacheHits = 0;
108 int fCacheMisses = 0;
109
110 int fNumSWCreations = 0;
Robert Phillips3380be92020-09-25 12:47:10 -0400111 int fNumLazyCreations = 0;
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400112 int fNumHWCreations = 0;
113 };
114
Robert Phillips67e58cb2020-11-02 08:57:39 -0500115 TestHelper(GrDirectContext* dContext,
116 GrThreadSafeCache::IsNewerBetter isNewerBetter = default_is_newer_better)
117 : fDContext(dContext)
118 , fIsNewerBetter(isNewerBetter) {
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400119
120 fDst = SkSurface::MakeRenderTarget(dContext, SkBudgeted::kNo, default_ii(kImageWH));
121 SkAssertResult(fDst);
122
123 SkSurfaceCharacterization characterization;
124 SkAssertResult(fDst->characterize(&characterization));
125
126 fRecorder1 = std::make_unique<SkDeferredDisplayListRecorder>(characterization);
Robert Phillips375e1f62020-10-23 16:13:57 -0400127 this->ddlCanvas1()->clear(SkColors::kWhite);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400128
129 fRecorder2 = std::make_unique<SkDeferredDisplayListRecorder>(characterization);
Robert Phillips375e1f62020-10-23 16:13:57 -0400130 this->ddlCanvas2()->clear(SkColors::kWhite);
131
132 fDst->getCanvas()->clear(SkColors::kWhite);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400133 }
134
135 ~TestHelper() {
Robert Phillips187b04b2020-09-22 12:18:16 -0400136 fDContext->flush();
137 fDContext->submit(true);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400138 }
139
140 Stats* stats() { return &fStats; }
141
Robert Phillipsd464feb2020-10-08 11:00:02 -0400142 int numCacheEntries() const { return this->threadSafeCache()->numEntries(); }
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400143
144 GrDirectContext* dContext() { return fDContext; }
145
146 SkCanvas* liveCanvas() { return fDst ? fDst->getCanvas() : nullptr; }
147 SkCanvas* ddlCanvas1() { return fRecorder1 ? fRecorder1->getCanvas() : nullptr; }
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400148 sk_sp<SkDeferredDisplayList> snap1() {
149 if (fRecorder1) {
150 sk_sp<SkDeferredDisplayList> tmp = fRecorder1->detach();
151 fRecorder1 = nullptr;
152 return tmp;
153 }
154
155 return nullptr;
156 }
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400157 SkCanvas* ddlCanvas2() { return fRecorder2 ? fRecorder2->getCanvas() : nullptr; }
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400158 sk_sp<SkDeferredDisplayList> snap2() {
159 if (fRecorder2) {
160 sk_sp<SkDeferredDisplayList> tmp = fRecorder2->detach();
161 fRecorder2 = nullptr;
162 return tmp;
163 }
164
165 return nullptr;
166 }
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400167
Robert Phillipsd464feb2020-10-08 11:00:02 -0400168 GrThreadSafeCache* threadSafeCache() { return fDContext->priv().threadSafeCache(); }
169 const GrThreadSafeCache* threadSafeCache() const { return fDContext->priv().threadSafeCache(); }
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400170
Robert Phillips375e1f62020-10-23 16:13:57 -0400171 typedef void (TestHelper::*addAccessFP)(SkCanvas*, int wh, int id,
172 bool failLookUp, bool failFillingIn);
173 typedef bool (TestHelper::*checkFP)(SkCanvas*, int wh,
174 int expectedHits, int expectedMisses,
175 int expectedNumRefs, int expectedID);
176
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400177 // Add a draw on 'canvas' that will introduce a ref on the 'wh' view
Robert Phillips375e1f62020-10-23 16:13:57 -0400178 void addViewAccess(SkCanvas* canvas,
179 int wh,
180 int id = kNoID,
181 bool failLookup = false,
182 bool failFillingIn = false) {
183 auto rContext = canvas->recordingContext();
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400184
Robert Phillipsd464feb2020-10-08 11:00:02 -0400185 auto view = AccessCachedView(rContext, this->threadSafeCache(),
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400186 wh, failLookup, failFillingIn, id, &fStats);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400187 SkASSERT(view);
188
Brian Salomon8f7d9532020-12-23 09:16:59 -0500189 auto sdc = SkCanvasPriv::TopDeviceSurfaceDrawContext(canvas);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400190
Brian Salomon8f7d9532020-12-23 09:16:59 -0500191 sdc->drawTexture(nullptr,
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400192 view,
193 kPremul_SkAlphaType,
194 GrSamplerState::Filter::kNearest,
195 GrSamplerState::MipmapMode::kNone,
196 SkBlendMode::kSrcOver,
Robert Phillipsdefd2232020-09-25 15:25:46 -0400197 {1.0f, 1.0f, 1.0f, 1.0f},
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400198 SkRect::MakeWH(wh, wh),
199 SkRect::MakeWH(wh, wh),
200 GrAA::kNo,
201 GrQuadAAFlags::kNone,
202 SkCanvas::kFast_SrcRectConstraint,
203 SkMatrix::I(),
204 nullptr);
205 }
206
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400207 // Besides checking that the number of refs and cache hits and misses are as expected, this
208 // method also validates that the unique key doesn't appear in any of the other caches.
Robert Phillips375e1f62020-10-23 16:13:57 -0400209 bool checkView(SkCanvas* canvas, int wh,
210 int expectedHits, int expectedMisses, int expectedNumRefs, int expectedID) {
211 if (fStats.fCacheHits != expectedHits || fStats.fCacheMisses != expectedMisses) {
Robert Phillips187b04b2020-09-22 12:18:16 -0400212 SkDebugf("Hits E: %d A: %d --- Misses E: %d A: %d\n",
Robert Phillips375e1f62020-10-23 16:13:57 -0400213 expectedHits, fStats.fCacheHits, expectedMisses, fStats.fCacheMisses);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400214 return false;
215 }
216
217 GrUniqueKey key;
Robert Phillips375e1f62020-10-23 16:13:57 -0400218 create_view_key(&key, wh, kNoID);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400219
Robert Phillipsd464feb2020-10-08 11:00:02 -0400220 auto threadSafeCache = this->threadSafeCache();
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400221
Robert Phillips375e1f62020-10-23 16:13:57 -0400222 auto [view, xtraData] = threadSafeCache->findWithData(key);
Robert Phillips187b04b2020-09-22 12:18:16 -0400223 if (!view.proxy()) {
224 return false;
225 }
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400226
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400227 if (expectedID < 0) {
Robert Phillips375e1f62020-10-23 16:13:57 -0400228 if (xtraData) {
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400229 return false;
230 }
231 } else {
Robert Phillips375e1f62020-10-23 16:13:57 -0400232 if (!xtraData) {
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400233 return false;
234 }
235
Robert Phillips375e1f62020-10-23 16:13:57 -0400236 const int* cachedID = static_cast<const int*>(xtraData->data());
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400237 if (*cachedID != expectedID) {
238 return false;
239 }
240 }
241
Robert Phillips375e1f62020-10-23 16:13:57 -0400242 if (!view.proxy()->refCntGreaterThan(expectedNumRefs+1) || // +1 for 'view's ref
243 view.proxy()->refCntGreaterThan(expectedNumRefs+2)) {
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400244 return false;
245 }
246
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400247 if (canvas) {
248 GrRecordingContext* rContext = canvas->recordingContext();
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400249 GrProxyProvider* recordingProxyProvider = rContext->priv().proxyProvider();
250 sk_sp<GrTextureProxy> result = recordingProxyProvider->findProxyByUniqueKey(key);
251 if (result) {
252 // views in this cache should never appear in the recorder's cache
253 return false;
254 }
255 }
256
257 {
258 GrProxyProvider* directProxyProvider = fDContext->priv().proxyProvider();
259 sk_sp<GrTextureProxy> result = directProxyProvider->findProxyByUniqueKey(key);
260 if (result) {
261 // views in this cache should never appear in the main proxy cache
262 return false;
263 }
264 }
265
266 {
267 auto resourceProvider = fDContext->priv().resourceProvider();
268 sk_sp<GrSurface> surf = resourceProvider->findByUniqueKey<GrSurface>(key);
269 if (surf) {
270 // the textures backing the views in this cache should never be discoverable in the
271 // resource cache
272 return false;
273 }
274 }
275
276 return true;
277 }
278
Robert Phillips67e58cb2020-11-02 08:57:39 -0500279 void addVertAccess(SkCanvas* canvas,
280 int wh,
281 int id,
282 bool failLookup,
283 bool failFillingIn,
284 GrThreadSafeVertexTestOp** createdOp);
285
Robert Phillips375e1f62020-10-23 16:13:57 -0400286 // Add a draw on 'canvas' that will introduce a ref on a 'wh' vertex data
287 void addVertAccess(SkCanvas* canvas,
288 int wh,
289 int id = kNoID,
290 bool failLookup = false,
Robert Phillips67e58cb2020-11-02 08:57:39 -0500291 bool failFillingIn = false) {
292 this->addVertAccess(canvas, wh, id, failLookup, failFillingIn, nullptr);
293 }
Robert Phillips375e1f62020-10-23 16:13:57 -0400294
295 bool checkVert(SkCanvas* canvas, int wh,
296 int expectedHits, int expectedMisses, int expectedNumRefs, int expectedID) {
297 if (fStats.fCacheHits != expectedHits || fStats.fCacheMisses != expectedMisses) {
298 SkDebugf("Hits E: %d A: %d --- Misses E: %d A: %d\n",
299 expectedHits, fStats.fCacheHits, expectedMisses, fStats.fCacheMisses);
300 return false;
301 }
302
303 GrUniqueKey key;
304 create_vert_key(&key, wh, kNoID);
305
306 auto threadSafeCache = this->threadSafeCache();
307
308 auto [vertData, xtraData] = threadSafeCache->findVertsWithData(key);
309 if (!vertData) {
310 return false;
311 }
312
313 if (expectedID < 0) {
314 if (xtraData) {
315 return false;
316 }
317 } else {
318 if (!xtraData) {
319 return false;
320 }
321
322 const int* cachedID = static_cast<const int*>(xtraData->data());
323 if (*cachedID != expectedID) {
324 return false;
325 }
326 }
327
328 if (!vertData->refCntGreaterThan(expectedNumRefs+1) || // +1 for 'vertData's ref
329 vertData->refCntGreaterThan(expectedNumRefs+2)) {
330 return false;
331 }
332
333 {
334 auto resourceProvider = fDContext->priv().resourceProvider();
335 sk_sp<GrGpuBuffer> buffer = resourceProvider->findByUniqueKey<GrGpuBuffer>(key);
336 if (buffer) {
337 // the buffer holding the vertex data in this cache should never be discoverable
338 // in the resource cache
339 return false;
340 }
341 }
342
343 return true;
344 }
345
Robert Phillipsdefd2232020-09-25 15:25:46 -0400346 bool checkImage(skiatest::Reporter* reporter, sk_sp<SkSurface> s) {
347 SkBitmap actual;
348
349 actual.allocPixels(default_ii(kImageWH));
350
351 if (!s->readPixels(actual, 0, 0)) {
352 return false;
353 }
354
355 SkBitmap expected = create_bitmap(kImageWH);
356
357 const float tols[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
358
359 auto error = std::function<ComparePixmapsErrorReporter>(
360 [reporter](int x, int y, const float diffs[4]) {
361 SkASSERT(x >= 0 && y >= 0);
362 ERRORF(reporter, "mismatch at %d, %d (%f, %f, %f %f)",
363 x, y, diffs[0], diffs[1], diffs[2], diffs[3]);
364 });
365
366 return ComparePixels(expected.pixmap(), actual.pixmap(), tols, error);
367 }
368
369 bool checkImage(skiatest::Reporter* reporter) {
370 return this->checkImage(reporter, fDst);
371 }
372
373 bool checkImage(skiatest::Reporter* reporter, sk_sp<SkDeferredDisplayList> ddl) {
374 sk_sp<SkSurface> tmp = SkSurface::MakeRenderTarget(fDContext,
375 SkBudgeted::kNo,
376 default_ii(kImageWH));
377 if (!tmp) {
378 return false;
379 }
380
381 if (!tmp->draw(std::move(ddl))) {
382 return false;
383 }
384
385 return this->checkImage(reporter, std::move(tmp));
386 }
387
Robert Phillips187b04b2020-09-22 12:18:16 -0400388 size_t gpuSize(int wh) const {
389 GrBackendFormat format = fDContext->defaultBackendFormat(kRGBA_8888_SkColorType,
390 GrRenderable::kNo);
391
Greg Daniel0eca74c2020-10-01 13:46:00 -0400392 return GrSurface::ComputeSize(format, {wh, wh}, /*colorSamplesPerPixel=*/1,
393 GrMipMapped::kNo, /*binSize=*/false);
Robert Phillips187b04b2020-09-22 12:18:16 -0400394 }
395
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400396private:
397 static GrSurfaceProxyView AccessCachedView(GrRecordingContext*,
Robert Phillipsd464feb2020-10-08 11:00:02 -0400398 GrThreadSafeCache*,
Robert Phillips187b04b2020-09-22 12:18:16 -0400399 int wh,
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400400 bool failLookup, bool failFillingIn, int id,
Robert Phillips3380be92020-09-25 12:47:10 -0400401 Stats*);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400402 static GrSurfaceProxyView CreateViewOnCpu(GrRecordingContext*, int wh, Stats*);
Robert Phillips3380be92020-09-25 12:47:10 -0400403 static bool FillInViewOnGpu(GrDirectContext*, int wh, Stats*,
404 const GrSurfaceProxyView& lazyView,
Robert Phillipsd464feb2020-10-08 11:00:02 -0400405 sk_sp<GrThreadSafeCache::Trampoline>);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400406
407 Stats fStats;
408 GrDirectContext* fDContext = nullptr;
Robert Phillips67e58cb2020-11-02 08:57:39 -0500409 GrThreadSafeCache::IsNewerBetter fIsNewerBetter;
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400410
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400411 sk_sp<SkSurface> fDst;
412 std::unique_ptr<SkDeferredDisplayListRecorder> fRecorder1;
413 std::unique_ptr<SkDeferredDisplayListRecorder> fRecorder2;
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400414};
415
Robert Phillips375e1f62020-10-23 16:13:57 -0400416class GrThreadSafeVertexTestOp : public GrDrawOp {
417public:
418 DEFINE_OP_CLASS_ID
419
Herb Derbyc76d4092020-10-07 16:46:15 -0400420 static GrOp::Owner Make(GrRecordingContext* rContext, TestHelper::Stats* stats,
Robert Phillips67e58cb2020-11-02 08:57:39 -0500421 int wh, int id, bool failLookup, bool failFillingIn,
422 GrThreadSafeCache::IsNewerBetter isNewerBetter) {
Robert Phillips375e1f62020-10-23 16:13:57 -0400423
Herb Derbyc76d4092020-10-07 16:46:15 -0400424 return GrOp::Make<GrThreadSafeVertexTestOp>(
Robert Phillips67e58cb2020-11-02 08:57:39 -0500425 rContext, rContext, stats, wh, id, failLookup, failFillingIn, isNewerBetter);
Robert Phillips375e1f62020-10-23 16:13:57 -0400426 }
427
Robert Phillips67e58cb2020-11-02 08:57:39 -0500428 const GrThreadSafeCache::VertexData* vertexData() const { return fVertexData.get(); }
429
Robert Phillips375e1f62020-10-23 16:13:57 -0400430private:
Herb Derbyc76d4092020-10-07 16:46:15 -0400431 friend class GrOp; // for ctor
Robert Phillips375e1f62020-10-23 16:13:57 -0400432
433 GrThreadSafeVertexTestOp(GrRecordingContext* rContext, TestHelper::Stats* stats, int wh, int id,
Robert Phillips67e58cb2020-11-02 08:57:39 -0500434 bool failLookup, bool failFillingIn,
435 GrThreadSafeCache::IsNewerBetter isNewerBetter)
Robert Phillips375e1f62020-10-23 16:13:57 -0400436 : INHERITED(ClassID())
437 , fStats(stats)
438 , fWH(wh)
439 , fID(id)
Robert Phillips67e58cb2020-11-02 08:57:39 -0500440 , fFailFillingIn(failFillingIn)
441 , fIsNewerBetter(isNewerBetter) {
Robert Phillips375e1f62020-10-23 16:13:57 -0400442 this->setBounds(SkRect::MakeIWH(fWH, fWH), HasAABloat::kNo, IsHairline::kNo);
443
444 // Normally we wouldn't add a ref to the vertex data at this point. However, it is
445 // needed in this unit test to get the ref counts on the uniquely keyed resources
446 // to be as expected.
447 this->findOrCreateVertices(rContext, failLookup, fFailFillingIn);
448 }
449
450 const char* name() const override { return "GrThreadSafeVertexTestOp"; }
451 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
Chris Dalton57ab06c2021-04-22 12:57:28 -0600452 GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override {
Robert Phillips375e1f62020-10-23 16:13:57 -0400453 return GrProcessorSet::EmptySetAnalysis();
454 }
455
456 GrProgramInfo* createProgramInfo(const GrCaps* caps,
457 SkArenaAlloc* arena,
Adlai Hollere2296f72020-11-19 13:41:26 -0500458 const GrSurfaceProxyView& writeView,
Robert Phillips375e1f62020-10-23 16:13:57 -0400459 GrAppliedClip&& appliedClip,
John Stiles52cb1d02021-06-02 11:58:05 -0400460 const GrDstProxyView& dstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -0500461 GrXferBarrierFlags renderPassXferBarriers,
462 GrLoadOp colorLoadOp) const {
Robert Phillips375e1f62020-10-23 16:13:57 -0400463 using namespace GrDefaultGeoProcFactory;
464
465 Color color({ 0.0f, 0.0f, 1.0f, 1.0f });
466
467 auto gp = MakeForDeviceSpace(arena, color,
468 Coverage::kSolid_Type,
469 LocalCoords::kUnused_Type,
470 SkMatrix::I());
471
472 return sk_gpu_test::CreateProgramInfo(caps, arena, writeView,
473 std::move(appliedClip), dstProxyView,
474 gp, SkBlendMode::kSrcOver,
475 GrPrimitiveType::kTriangleStrip,
Greg Daniel42dbca52020-11-20 10:22:43 -0500476 renderPassXferBarriers, colorLoadOp);
Robert Phillips375e1f62020-10-23 16:13:57 -0400477 }
478
479 GrProgramInfo* createProgramInfo(GrOpFlushState* flushState) const {
480 return this->createProgramInfo(&flushState->caps(),
481 flushState->allocator(),
482 flushState->writeView(),
483 flushState->detachAppliedClip(),
484 flushState->dstProxyView(),
Greg Daniel42dbca52020-11-20 10:22:43 -0500485 flushState->renderPassBarriers(),
486 flushState->colorLoadOp());
Robert Phillips375e1f62020-10-23 16:13:57 -0400487 }
488
489 void findOrCreateVertices(GrRecordingContext* rContext, bool failLookup, bool failFillingIn) {
490
491 if (!fVertexData) {
492 auto threadSafeViewCache = rContext->priv().threadSafeCache();
493
494 if (rContext->asDirectContext()) {
495 // The vertex variant doesn't have a correlate to lazyProxies but increment this
496 // here to make the unit tests happy.
497 ++fStats->fNumLazyCreations;
498 }
499
500 GrUniqueKey key;
501 create_vert_key(&key, fWH, fID);
502
503 // We can "fail the lookup" to simulate a threaded race condition
504 auto [cachedVerts, data] = threadSafeViewCache->findVertsWithData(key);
505 if (cachedVerts && !failLookup) {
506 fVertexData = cachedVerts;
507 ++fStats->fCacheHits;
508 return;
509 }
510
511 ++fStats->fCacheMisses;
512 if (!rContext->asDirectContext()) {
513 ++fStats->fNumSWCreations;
514 }
515
516 constexpr size_t kVertSize = sizeof(SkPoint);
517 SkPoint* verts = static_cast<SkPoint*>(sk_malloc_throw(4 * kVertSize));
518
519 verts[0].set(10.0f, 10.0f);
520 verts[1].set(fWH-10.0f, 10.0f);
521 verts[2].set(10.0f, fWH-10.0f);
522 verts[3].set(fWH-10.0f, fWH-10.0f);
523
524 fVertexData = GrThreadSafeCache::MakeVertexData(verts, 4, kVertSize);
525
Robert Phillips67e58cb2020-11-02 08:57:39 -0500526 auto [tmpV, tmpD] = threadSafeViewCache->addVertsWithData(key, fVertexData,
527 fIsNewerBetter);
Robert Phillips375e1f62020-10-23 16:13:57 -0400528 if (tmpV != fVertexData) {
529 // Someone beat us to creating the vertex data. Use that version.
530 fVertexData = tmpV;
531 }
532 }
533
534 if (auto dContext = rContext->asDirectContext(); dContext && !fVertexData->gpuBuffer()) {
535 auto rp = dContext->priv().resourceProvider();
536
537 if (!failFillingIn) {
538 ++fStats->fNumHWCreations;
539
540 sk_sp<GrGpuBuffer> tmp = rp->createBuffer(fVertexData->size(),
541 GrGpuBufferType::kVertex,
542 kStatic_GrAccessPattern,
543 fVertexData->vertices());
544 fVertexData->setGpuBuffer(std::move(tmp));
545 }
546 }
547 }
548
549 void onPrePrepare(GrRecordingContext* rContext,
Adlai Hollere2296f72020-11-19 13:41:26 -0500550 const GrSurfaceProxyView& writeView,
Robert Phillips375e1f62020-10-23 16:13:57 -0400551 GrAppliedClip* clip,
John Stiles52cb1d02021-06-02 11:58:05 -0400552 const GrDstProxyView& dstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -0500553 GrXferBarrierFlags renderPassXferBarriers,
554 GrLoadOp colorLoadOp) override {
Robert Phillips375e1f62020-10-23 16:13:57 -0400555 SkArenaAlloc* arena = rContext->priv().recordTimeAllocator();
556
557 // This is equivalent to a GrOpFlushState::detachAppliedClip
558 GrAppliedClip appliedClip = clip ? std::move(*clip) : GrAppliedClip::Disabled();
559
560 fProgramInfo = this->createProgramInfo(rContext->priv().caps(), arena, writeView,
561 std::move(appliedClip), dstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -0500562 renderPassXferBarriers, colorLoadOp);
Robert Phillips375e1f62020-10-23 16:13:57 -0400563
564 rContext->priv().recordProgramInfo(fProgramInfo);
565
566 // This is now a noop (bc it is always called in the ctor) but is where we would normally
567 // create the vertices.
568 this->findOrCreateVertices(rContext, false, fFailFillingIn);
569 }
570
571 void onPrepare(GrOpFlushState* flushState) override {
572 auto dContext = flushState->gpu()->getContext();
573
574 // This call site is not a noop bc this op could've been created on with DDL context
575 // and, therefore, could be lacking a gpu-side buffer
576 this->findOrCreateVertices(dContext, false, fFailFillingIn);
577 }
578
579 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
580 if (!fVertexData || !fVertexData->gpuBuffer()) {
581 return;
582 }
583
584 if (!fProgramInfo) {
585 fProgramInfo = this->createProgramInfo(flushState);
586 }
587
588 flushState->bindPipeline(*fProgramInfo, SkRect::MakeIWH(fWH, fWH));
589 flushState->bindBuffers(nullptr, nullptr, fVertexData->refGpuBuffer());
590 flushState->draw(4, 0);
591 }
592
Robert Phillips67e58cb2020-11-02 08:57:39 -0500593 TestHelper::Stats* fStats;
594 int fWH;
595 int fID;
596 bool fFailFillingIn;
597 GrThreadSafeCache::IsNewerBetter fIsNewerBetter;
Robert Phillips375e1f62020-10-23 16:13:57 -0400598
599 sk_sp<GrThreadSafeCache::VertexData> fVertexData;
Robert Phillips67e58cb2020-11-02 08:57:39 -0500600 GrProgramInfo* fProgramInfo = nullptr;
Robert Phillips375e1f62020-10-23 16:13:57 -0400601
602 using INHERITED = GrDrawOp;
603};
604
605void TestHelper::addVertAccess(SkCanvas* canvas,
606 int wh, int id,
Robert Phillips67e58cb2020-11-02 08:57:39 -0500607 bool failLookup, bool failFillingIn,
608 GrThreadSafeVertexTestOp** createdOp) {
Robert Phillips375e1f62020-10-23 16:13:57 -0400609 auto rContext = canvas->recordingContext();
Brian Salomon8f7d9532020-12-23 09:16:59 -0500610 auto sdc = SkCanvasPriv::TopDeviceSurfaceDrawContext(canvas);
Robert Phillips375e1f62020-10-23 16:13:57 -0400611
Robert Phillips67e58cb2020-11-02 08:57:39 -0500612 GrOp::Owner op = GrThreadSafeVertexTestOp::Make(rContext, &fStats,
613 wh, id,
614 failLookup, failFillingIn,
615 fIsNewerBetter);
616 if (createdOp) {
617 *createdOp = (GrThreadSafeVertexTestOp*) op.get();
618 }
619
Brian Salomon8f7d9532020-12-23 09:16:59 -0500620 sdc->addDrawOp(std::move(op));
Robert Phillips375e1f62020-10-23 16:13:57 -0400621}
622
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400623GrSurfaceProxyView TestHelper::CreateViewOnCpu(GrRecordingContext* rContext,
624 int wh,
625 Stats* stats) {
626 GrProxyProvider* proxyProvider = rContext->priv().proxyProvider();
627
Robert Phillips3380be92020-09-25 12:47:10 -0400628 sk_sp<GrTextureProxy> proxy = proxyProvider->createProxyFromBitmap(create_bitmap(wh),
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400629 GrMipmapped::kNo,
630 SkBackingFit::kExact,
631 SkBudgeted::kYes);
632 if (!proxy) {
633 return {};
634 }
635
636 GrSwizzle swizzle = rContext->priv().caps()->getReadSwizzle(proxy->backendFormat(),
637 GrColorType::kRGBA_8888);
638 ++stats->fNumSWCreations;
639 return {std::move(proxy), kImageOrigin, swizzle};
640}
641
Robert Phillipsd464feb2020-10-08 11:00:02 -0400642bool TestHelper::FillInViewOnGpu(GrDirectContext* dContext, int wh, Stats* stats,
643 const GrSurfaceProxyView& lazyView,
644 sk_sp<GrThreadSafeCache::Trampoline> trampoline) {
Robert Phillips3380be92020-09-25 12:47:10 -0400645
Robert Phillips4dca8312021-07-28 15:13:20 -0400646 std::unique_ptr<skgpu::v1::SurfaceDrawContext> sdc = new_SDC(dContext, wh);
Robert Phillips3380be92020-09-25 12:47:10 -0400647
648 GrPaint paint;
649 paint.setColor4f({0.0f, 0.0f, 1.0f, 1.0f});
650
Robert Phillips4dca8312021-07-28 15:13:20 -0400651 sdc->clear(SkPMColor4f{1.0f, 1.0f, 1.0f, 1.0f});
652 sdc->drawRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(),
Robert Phillips3380be92020-09-25 12:47:10 -0400653 { 10, 10, wh-10.0f, wh-10.0f }, &GrStyle::SimpleFill());
654
655 ++stats->fNumHWCreations;
Robert Phillips4dca8312021-07-28 15:13:20 -0400656 auto view = sdc->readSurfaceView();
Robert Phillips3380be92020-09-25 12:47:10 -0400657
658 SkASSERT(view.swizzle() == lazyView.swizzle());
659 SkASSERT(view.origin() == lazyView.origin());
660 trampoline->fProxy = view.asTextureProxyRef();
661
662 return true;
663}
664
Robert Phillipsd464feb2020-10-08 11:00:02 -0400665GrSurfaceProxyView TestHelper::AccessCachedView(GrRecordingContext* rContext,
666 GrThreadSafeCache* threadSafeCache,
667 int wh,
668 bool failLookup, bool failFillingIn, int id,
669 Stats* stats) {
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400670 GrUniqueKey key;
Robert Phillips375e1f62020-10-23 16:13:57 -0400671 create_view_key(&key, wh, id);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400672
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400673 if (GrDirectContext* dContext = rContext->asDirectContext()) {
Robert Phillips3380be92020-09-25 12:47:10 -0400674 // The gpu thread gets priority over the recording threads. If the gpu thread is first,
675 // it crams a lazy proxy into the cache and then fills it in later.
Robert Phillipsd464feb2020-10-08 11:00:02 -0400676 auto [lazyView, trampoline] = GrThreadSafeCache::CreateLazyView(
Robert Phillipsfde67e42020-10-07 15:33:43 -0400677 dContext, GrColorType::kRGBA_8888, {wh, wh}, kImageOrigin, SkBackingFit::kExact);
Robert Phillipsb1807122020-10-06 16:44:18 -0400678 ++stats->fNumLazyCreations;
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400679
Robert Phillipsd464feb2020-10-08 11:00:02 -0400680 auto [view, data] = threadSafeCache->findOrAddWithData(key, lazyView);
Robert Phillips3380be92020-09-25 12:47:10 -0400681 if (view != lazyView) {
682 ++stats->fCacheHits;
683 return view;
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400684 } else if (id != kNoID) {
685 // Make sure, in this case, that the customData stuck
686 SkASSERT(data);
687 SkDEBUGCODE(const int* cachedID = static_cast<const int*>(data->data());)
688 SkASSERT(*cachedID == id);
Robert Phillips3380be92020-09-25 12:47:10 -0400689 }
690
691 ++stats->fCacheMisses;
692
693 if (failFillingIn) {
694 // Simulate something going horribly wrong at flush-time so no GrTexture is
695 // available to fulfill the lazy proxy.
696 return view;
697 }
698
699 if (!FillInViewOnGpu(dContext, wh, stats, lazyView, std::move(trampoline))) {
700 // In this case something has gone disastrously wrong so set up to drop the draw
701 // that needed this resource and reduce future pollution of the cache.
Robert Phillipsd464feb2020-10-08 11:00:02 -0400702 threadSafeCache->remove(key);
Robert Phillips3380be92020-09-25 12:47:10 -0400703 return {};
704 }
705
706 return view;
707 } else {
708 GrSurfaceProxyView view;
709
710 // We can "fail the lookup" to simulate a threaded race condition
Robert Phillipsd464feb2020-10-08 11:00:02 -0400711 if (view = threadSafeCache->find(key); !failLookup && view) {
Robert Phillips3380be92020-09-25 12:47:10 -0400712 ++stats->fCacheHits;
713 return view;
714 }
715
716 ++stats->fCacheMisses;
717
718 view = CreateViewOnCpu(rContext, wh, stats);
719 SkASSERT(view);
720
Robert Phillipsd464feb2020-10-08 11:00:02 -0400721 auto [newView, data] = threadSafeCache->addWithData(key, view);
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400722 if (view == newView && id != kNoID) {
723 // Make sure, in this case, that the customData stuck
724 SkASSERT(data);
725 SkDEBUGCODE(const int* cachedID = static_cast<const int*>(data->data());)
726 SkASSERT(*cachedID == id);
727 }
728 return newView;
Robert Phillips3380be92020-09-25 12:47:10 -0400729 }
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400730}
731
Robert Phillips375e1f62020-10-23 16:13:57 -0400732// Case 1: ensure two DDL recorders share the view/vertexData
733static void test_1(GrDirectContext* dContext, skiatest::Reporter* reporter,
734 TestHelper::addAccessFP addAccess,
735 TestHelper::checkFP check) {
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400736
Robert Phillips375e1f62020-10-23 16:13:57 -0400737 TestHelper helper(dContext);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400738
Robert Phillips375e1f62020-10-23 16:13:57 -0400739 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, 1, false, false);
740 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
741 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, /*id*/ 1));
742
743 (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, 2, false, false);
744 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), kImageWH,
745 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, /*id*/ 1));
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400746
747 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips3380be92020-09-25 12:47:10 -0400748 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 0);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400749 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 0);
750 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 1);
Robert Phillipsdefd2232020-09-25 15:25:46 -0400751
752 helper.checkImage(reporter, helper.snap1());
753 helper.checkImage(reporter, helper.snap2());
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400754}
755
Robert Phillips375e1f62020-10-23 16:13:57 -0400756DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache1View, reporter, ctxInfo) {
757 test_1(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
758}
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400759
Robert Phillips375e1f62020-10-23 16:13:57 -0400760DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache1Verts, reporter, ctxInfo) {
761 test_1(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
762}
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400763
Robert Phillips375e1f62020-10-23 16:13:57 -0400764// Case 2: ensure that, if the direct context version wins, its result is reused by the
765// DDL recorders
766static void test_2(GrDirectContext* dContext, skiatest::Reporter* reporter,
767 TestHelper::addAccessFP addAccess,
768 TestHelper::checkFP check) {
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400769
Robert Phillips375e1f62020-10-23 16:13:57 -0400770 TestHelper helper(dContext);
771
772 (helper.*addAccess)(helper.liveCanvas(), kImageWH, 1, false, false);
773 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
774 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, /*id*/ 1));
775
776 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, 2, false, false);
777 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
778 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, /*id*/ 1));
779
780 (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, 3, false, false);
781 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), kImageWH,
782 /*hits*/ 2, /*misses*/ 1, /*refs*/ 3, /*id*/ 1));
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400783
784 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips3380be92020-09-25 12:47:10 -0400785 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400786 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 1);
787 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0);
Robert Phillipsdefd2232020-09-25 15:25:46 -0400788
789 helper.checkImage(reporter);
790 helper.checkImage(reporter, helper.snap1());
791 helper.checkImage(reporter, helper.snap2());
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400792}
793
Robert Phillips375e1f62020-10-23 16:13:57 -0400794DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache2View, reporter, ctxInfo) {
795 test_2(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
796}
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400797
Robert Phillips375e1f62020-10-23 16:13:57 -0400798DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache2Verts, reporter, ctxInfo) {
799 test_2(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
800}
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400801
Robert Phillips375e1f62020-10-23 16:13:57 -0400802// Case 3: ensure that, if the cpu-version wins, its result is reused by the direct context
803static void test_3(GrDirectContext* dContext, skiatest::Reporter* reporter,
804 TestHelper::addAccessFP addAccess,
805 TestHelper::checkFP check) {
806
807 TestHelper helper(dContext);
808
809 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, 1, false, false);
810 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
811 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, /*id*/ 1));
812
813 (helper.*addAccess)(helper.liveCanvas(), kImageWH, 2, false, false);
814 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
815 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, /*id*/ 1));
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400816
817 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips3380be92020-09-25 12:47:10 -0400818 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400819 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 0);
820 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 1);
Robert Phillipsdefd2232020-09-25 15:25:46 -0400821
822 helper.checkImage(reporter);
823 helper.checkImage(reporter, helper.snap1());
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400824}
825
Robert Phillips375e1f62020-10-23 16:13:57 -0400826DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache3View, reporter, ctxInfo) {
827 test_3(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
828}
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400829
Robert Phillips375e1f62020-10-23 16:13:57 -0400830DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache3Verts, reporter, ctxInfo) {
831 test_3(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
832}
833
834// Case 4: ensure that, if two DDL recorders get in a race, they still end up sharing a single
835// view/vertexData
836static void test_4(GrDirectContext* dContext, skiatest::Reporter* reporter,
837 TestHelper::addAccessFP addAccess,
838 TestHelper::checkFP check) {
839
840 TestHelper helper(dContext);
841
842 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, 1, false, false);
843 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
844 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, /*id*/ 1));
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400845
846 static const bool kFailLookup = true;
Robert Phillips375e1f62020-10-23 16:13:57 -0400847 (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, 2, kFailLookup, false);
848 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), kImageWH,
849 /*hits*/ 0, /*misses*/ 2, /*refs*/ 2, /*id*/ 1));
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400850
851 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips3380be92020-09-25 12:47:10 -0400852 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 0);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400853 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 0);
854 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 2);
Robert Phillipsdefd2232020-09-25 15:25:46 -0400855
856 helper.checkImage(reporter, helper.snap1());
857 helper.checkImage(reporter, helper.snap2());
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400858}
Robert Phillips752f7e12020-09-18 12:28:59 -0400859
Robert Phillips375e1f62020-10-23 16:13:57 -0400860DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache4View, reporter, ctxInfo) {
861 test_4(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
862}
Robert Phillips3380be92020-09-25 12:47:10 -0400863
Robert Phillips375e1f62020-10-23 16:13:57 -0400864DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache4Verts, reporter, ctxInfo) {
865 test_4(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
866}
867
868// Case 4.5: check that, if a live rendering and a DDL recording get into a race, the live
869// rendering takes precedence.
870static void test_4_5(GrDirectContext* dContext, skiatest::Reporter* reporter,
871 TestHelper::addAccessFP addAccess,
872 TestHelper::checkFP check) {
873
874 TestHelper helper(dContext);
875
876 (helper.*addAccess)(helper.liveCanvas(), kImageWH, 1, false, false);
877 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
878 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, /*id*/ 1));
Robert Phillips3380be92020-09-25 12:47:10 -0400879
880 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
881 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
882 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 1);
883 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0);
884
885 static const bool kFailLookup = true;
Robert Phillips375e1f62020-10-23 16:13:57 -0400886 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, 2, kFailLookup, false);
887 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
888 /*hits*/ 0, /*misses*/ 2, /*refs*/ 2, /*id*/ 1));
Robert Phillips3380be92020-09-25 12:47:10 -0400889
890 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
891 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
892 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 1);
893 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 1);
Robert Phillipsdefd2232020-09-25 15:25:46 -0400894
895 helper.checkImage(reporter);
896 helper.checkImage(reporter, helper.snap1());
Robert Phillips3380be92020-09-25 12:47:10 -0400897}
898
Robert Phillips375e1f62020-10-23 16:13:57 -0400899DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache4_5View, reporter, ctxInfo) {
900 test_4_5(ctxInfo.directContext(), reporter,
901 &TestHelper::addViewAccess, &TestHelper::checkView);
902}
903
904DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache4_5Verts, reporter, ctxInfo) {
905 test_4_5(ctxInfo.directContext(), reporter,
906 &TestHelper::addVertAccess, &TestHelper::checkVert);
907}
908
Robert Phillips3380be92020-09-25 12:47:10 -0400909// Case 4.75: check that, if a live rendering fails to generate the content needed to instantiate
910// its lazy proxy, life goes on
Robert Phillips375e1f62020-10-23 16:13:57 -0400911static void test_4_75(GrDirectContext* dContext, skiatest::Reporter* reporter,
912 TestHelper::addAccessFP addAccess,
913 TestHelper::checkFP check) {
Robert Phillips3380be92020-09-25 12:47:10 -0400914
915 TestHelper helper(dContext);
916
917 static const bool kFailFillingIn = true;
Robert Phillips375e1f62020-10-23 16:13:57 -0400918 (helper.*addAccess)(helper.liveCanvas(), kImageWH, kNoID, false, kFailFillingIn);
919 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
920 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
Robert Phillips3380be92020-09-25 12:47:10 -0400921
922 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
923 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
924 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 0);
925 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0);
926
927 dContext->flush();
928 dContext->submit(true);
929
Robert Phillips375e1f62020-10-23 16:13:57 -0400930 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
931 /*hits*/ 0, /*misses*/ 1, /*refs*/ 0, kNoID));
Robert Phillips3380be92020-09-25 12:47:10 -0400932
933 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
934 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
935 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 0);
936 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0);
937}
938
Robert Phillips375e1f62020-10-23 16:13:57 -0400939DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache4_75View, reporter, ctxInfo) {
940 test_4_75(ctxInfo.directContext(), reporter,
941 &TestHelper::addViewAccess, &TestHelper::checkView);
942}
943
944DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache4_75Verts, reporter, ctxInfo) {
945 test_4_75(ctxInfo.directContext(), reporter,
946 &TestHelper::addVertAccess, &TestHelper::checkVert);
947}
948
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400949// Case 5: ensure that expanding the map works (esp. wrt custom data)
Robert Phillips375e1f62020-10-23 16:13:57 -0400950static void test_5(GrDirectContext* dContext, skiatest::Reporter* reporter,
951 TestHelper::addAccessFP addAccess,
952 TestHelper::checkFP check) {
953
954 TestHelper helper(dContext);
Robert Phillips752f7e12020-09-18 12:28:59 -0400955
Robert Phillipsd464feb2020-10-08 11:00:02 -0400956 auto threadSafeCache = helper.threadSafeCache();
Robert Phillips752f7e12020-09-18 12:28:59 -0400957
958 int size = 16;
Robert Phillips375e1f62020-10-23 16:13:57 -0400959 (helper.*addAccess)(helper.ddlCanvas1(), size, /*id*/ size, false, false);
Robert Phillips752f7e12020-09-18 12:28:59 -0400960
Robert Phillipsd464feb2020-10-08 11:00:02 -0400961 size_t initialSize = threadSafeCache->approxBytesUsedForHash();
Robert Phillips752f7e12020-09-18 12:28:59 -0400962
Robert Phillipsd464feb2020-10-08 11:00:02 -0400963 while (initialSize == threadSafeCache->approxBytesUsedForHash()) {
Robert Phillips752f7e12020-09-18 12:28:59 -0400964 size *= 2;
Robert Phillips375e1f62020-10-23 16:13:57 -0400965 (helper.*addAccess)(helper.ddlCanvas1(), size, /*id*/ size, false, false);
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400966 }
967
968 for (int i = 16; i <= size; i *= 2) {
Robert Phillips375e1f62020-10-23 16:13:57 -0400969 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(),
970 /*wh*/ i,
971 /*hits*/ 0,
972 /*misses*/ threadSafeCache->numEntries(),
973 /*refs*/ 1,
974 /*id*/ i));
Robert Phillips752f7e12020-09-18 12:28:59 -0400975 }
976}
977
Robert Phillips375e1f62020-10-23 16:13:57 -0400978DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache5View, reporter, ctxInfo) {
979 test_5(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
980}
981
982DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache5Verts, reporter, ctxInfo) {
983 test_5(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
984}
985
Robert Phillipsdefd2232020-09-25 15:25:46 -0400986// Case 6: Check on dropping refs. In particular, that the cache has its own ref to keep
Robert Phillips375e1f62020-10-23 16:13:57 -0400987// the backing resource alive and locked.
988static void test_6(GrDirectContext* dContext, skiatest::Reporter* reporter,
989 TestHelper::addAccessFP addAccess,
990 TestHelper::checkFP check) {
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400991
Robert Phillips375e1f62020-10-23 16:13:57 -0400992 TestHelper helper(dContext);
993
994 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false);
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400995 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
Robert Phillips375e1f62020-10-23 16:13:57 -0400996 REPORTER_ASSERT(reporter, (helper.*check)(nullptr, kImageWH,
997 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400998
Robert Phillips375e1f62020-10-23 16:13:57 -0400999 (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, kNoID, false, false);
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -04001000 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
Robert Phillips375e1f62020-10-23 16:13:57 -04001001 REPORTER_ASSERT(reporter, (helper.*check)(nullptr, kImageWH,
1002 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, kNoID));
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -04001003
1004 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
1005
1006 ddl1 = nullptr;
Robert Phillips375e1f62020-10-23 16:13:57 -04001007 REPORTER_ASSERT(reporter, (helper.*check)(nullptr, kImageWH,
1008 /*hits*/ 1, /*misses*/ 1, /*refs*/ 1, kNoID));
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -04001009
1010 ddl2 = nullptr;
Robert Phillips375e1f62020-10-23 16:13:57 -04001011 REPORTER_ASSERT(reporter, (helper.*check)(nullptr, kImageWH,
1012 /*hits*/ 1, /*misses*/ 1, /*refs*/ 0, kNoID));
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -04001013
1014 // The cache still has its ref
1015 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
1016
Robert Phillips375e1f62020-10-23 16:13:57 -04001017 REPORTER_ASSERT(reporter, (helper.*check)(nullptr, kImageWH,
1018 /*hits*/ 1, /*misses*/ 1, /*refs*/ 0, kNoID));
1019}
1020
1021DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache6View, reporter, ctxInfo) {
1022 test_6(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
1023}
1024
1025DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache6Verts, reporter, ctxInfo) {
1026 test_6(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -04001027}
Robert Phillips45593682020-09-18 16:16:33 -04001028
Robert Phillipsdefd2232020-09-25 15:25:46 -04001029// Case 7: Check that invoking dropAllRefs and dropUniqueRefs directly works as expected; i.e.,
Robert Phillips375e1f62020-10-23 16:13:57 -04001030// dropAllRefs removes everything while dropUniqueRefs is more measured.
1031static void test_7(GrDirectContext* dContext, skiatest::Reporter* reporter,
1032 TestHelper::addAccessFP addAccess,
1033 TestHelper::checkFP check) {
Robert Phillips45593682020-09-18 16:16:33 -04001034
Robert Phillips375e1f62020-10-23 16:13:57 -04001035 TestHelper helper(dContext);
1036
1037 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false);
Robert Phillips45593682020-09-18 16:16:33 -04001038 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
Robert Phillips375e1f62020-10-23 16:13:57 -04001039 REPORTER_ASSERT(reporter, (helper.*check)(nullptr, kImageWH,
1040 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
Robert Phillips45593682020-09-18 16:16:33 -04001041
Robert Phillips375e1f62020-10-23 16:13:57 -04001042 (helper.*addAccess)(helper.ddlCanvas2(), 2*kImageWH, kNoID, false, false);
Robert Phillips45593682020-09-18 16:16:33 -04001043 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
Robert Phillips375e1f62020-10-23 16:13:57 -04001044 REPORTER_ASSERT(reporter, (helper.*check)(nullptr, 2*kImageWH,
1045 /*hits*/ 0, /*misses*/ 2, /*refs*/ 1, kNoID));
Robert Phillips45593682020-09-18 16:16:33 -04001046
1047 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
1048
Robert Phillipsd464feb2020-10-08 11:00:02 -04001049 helper.threadSafeCache()->dropUniqueRefs(nullptr);
Robert Phillips45593682020-09-18 16:16:33 -04001050 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
1051
1052 ddl1 = nullptr;
1053
Robert Phillipsd464feb2020-10-08 11:00:02 -04001054 helper.threadSafeCache()->dropUniqueRefs(nullptr);
Robert Phillips45593682020-09-18 16:16:33 -04001055 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips375e1f62020-10-23 16:13:57 -04001056 REPORTER_ASSERT(reporter, (helper.*check)(nullptr, 2*kImageWH,
1057 /*hits*/ 0, /*misses*/ 2, /*refs*/ 1, kNoID));
Robert Phillips45593682020-09-18 16:16:33 -04001058
Robert Phillipsd464feb2020-10-08 11:00:02 -04001059 helper.threadSafeCache()->dropAllRefs();
Robert Phillips45593682020-09-18 16:16:33 -04001060 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0);
1061
1062 ddl2 = nullptr;
1063}
Robert Phillips187b04b2020-09-22 12:18:16 -04001064
Robert Phillips375e1f62020-10-23 16:13:57 -04001065DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache7View, reporter, ctxInfo) {
1066 test_7(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
1067}
1068
1069DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache7Verts, reporter, ctxInfo) {
1070 test_7(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
1071}
1072
Robert Phillips187b04b2020-09-22 12:18:16 -04001073// Case 8: This checks that GrContext::abandonContext works as expected wrt the thread
1074// safe cache. This simulates the case where we have one DDL that has finished
1075// recording but one still recording when the abandonContext fires.
Robert Phillips375e1f62020-10-23 16:13:57 -04001076static void test_8(GrDirectContext* dContext, skiatest::Reporter* reporter,
1077 TestHelper::addAccessFP addAccess,
1078 TestHelper::checkFP check) {
Robert Phillips187b04b2020-09-22 12:18:16 -04001079
Robert Phillips375e1f62020-10-23 16:13:57 -04001080 TestHelper helper(dContext);
Robert Phillips187b04b2020-09-22 12:18:16 -04001081
Robert Phillips375e1f62020-10-23 16:13:57 -04001082 (helper.*addAccess)(helper.liveCanvas(), kImageWH, kNoID, false, false);
1083 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
1084 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
1085
1086 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false);
Robert Phillips187b04b2020-09-22 12:18:16 -04001087 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
Robert Phillips375e1f62020-10-23 16:13:57 -04001088 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
1089 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001090
Robert Phillips375e1f62020-10-23 16:13:57 -04001091 (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, kNoID, false, false);
1092 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), kImageWH,
1093 /*hits*/ 2, /*misses*/ 1, /*refs*/ 3, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001094
1095 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips3380be92020-09-25 12:47:10 -04001096 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
Robert Phillips187b04b2020-09-22 12:18:16 -04001097 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 1);
1098 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0);
1099
Robert Phillips375e1f62020-10-23 16:13:57 -04001100 dContext->abandonContext(); // This should exercise dropAllRefs
Robert Phillips187b04b2020-09-22 12:18:16 -04001101
1102 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
1103
1104 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0);
1105
1106 ddl1 = nullptr;
1107 ddl2 = nullptr;
1108}
1109
Robert Phillips375e1f62020-10-23 16:13:57 -04001110DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache8View, reporter, ctxInfo) {
1111 test_8(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
1112}
1113
1114DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache8Verts, reporter, ctxInfo) {
1115 test_8(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
1116}
1117
Robert Phillips187b04b2020-09-22 12:18:16 -04001118// Case 9: This checks that GrContext::releaseResourcesAndAbandonContext works as expected wrt
1119// the thread safe cache. This simulates the case where we have one DDL that has finished
1120// recording but one still recording when the releaseResourcesAndAbandonContext fires.
Robert Phillips375e1f62020-10-23 16:13:57 -04001121static void test_9(GrDirectContext* dContext, skiatest::Reporter* reporter,
1122 TestHelper::addAccessFP addAccess,
1123 TestHelper::checkFP check) {
Robert Phillips187b04b2020-09-22 12:18:16 -04001124
Robert Phillips375e1f62020-10-23 16:13:57 -04001125 TestHelper helper(dContext);
Robert Phillips187b04b2020-09-22 12:18:16 -04001126
Robert Phillips375e1f62020-10-23 16:13:57 -04001127 (helper.*addAccess)(helper.liveCanvas(), kImageWH, kNoID, false, false);
1128 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
1129 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
1130
1131 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false);
Robert Phillips187b04b2020-09-22 12:18:16 -04001132 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
Robert Phillips375e1f62020-10-23 16:13:57 -04001133 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
1134 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001135
Robert Phillips375e1f62020-10-23 16:13:57 -04001136 (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, kNoID, false, false);
1137 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), kImageWH,
1138 /*hits*/ 2, /*misses*/ 1, /*refs*/ 3, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001139
1140 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips3380be92020-09-25 12:47:10 -04001141 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
Robert Phillips187b04b2020-09-22 12:18:16 -04001142 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 1);
1143 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0);
1144
Robert Phillips375e1f62020-10-23 16:13:57 -04001145 dContext->releaseResourcesAndAbandonContext(); // This should hit dropAllRefs
Robert Phillips187b04b2020-09-22 12:18:16 -04001146
1147 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
1148
1149 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0);
1150
1151 ddl1 = nullptr;
1152 ddl2 = nullptr;
1153}
1154
Robert Phillips375e1f62020-10-23 16:13:57 -04001155DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache9View, reporter, ctxInfo) {
1156 test_9(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
1157}
1158
1159DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache9Verts, reporter, ctxInfo) {
1160 test_9(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
1161}
1162
Robert Phillips187b04b2020-09-22 12:18:16 -04001163// Case 10: This checks that the GrContext::purgeUnlockedResources(size_t) variant works as
1164// expected wrt the thread safe cache. It, in particular, tests out the MRU behavior
1165// of the shared cache.
Robert Phillips375e1f62020-10-23 16:13:57 -04001166static void test_10(GrDirectContext* dContext, skiatest::Reporter* reporter,
1167 TestHelper::addAccessFP addAccess,
1168 TestHelper::checkFP check) {
Brian Salomonb8c4add2021-06-28 09:20:44 -04001169
1170 if (GrBackendApi::kOpenGL != dContext->backend()) {
1171 // The lower-level backends have too much going on for the following simple purging
1172 // test to work
1173 return;
1174 }
1175
Robert Phillips187b04b2020-09-22 12:18:16 -04001176 TestHelper helper(dContext);
1177
Robert Phillips375e1f62020-10-23 16:13:57 -04001178 (helper.*addAccess)(helper.liveCanvas(), kImageWH, kNoID, false, false);
1179 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
1180 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001181
Robert Phillips375e1f62020-10-23 16:13:57 -04001182 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false);
Robert Phillips187b04b2020-09-22 12:18:16 -04001183 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
Robert Phillips375e1f62020-10-23 16:13:57 -04001184 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
1185 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001186
Robert Phillips375e1f62020-10-23 16:13:57 -04001187 (helper.*addAccess)(helper.liveCanvas(), 2*kImageWH, kNoID, false, false);
1188 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH,
1189 /*hits*/ 1, /*misses*/ 2, /*refs*/ 1, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001190
Robert Phillips375e1f62020-10-23 16:13:57 -04001191 (helper.*addAccess)(helper.ddlCanvas2(), 2*kImageWH, kNoID, false, false);
Robert Phillips187b04b2020-09-22 12:18:16 -04001192 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
Robert Phillips375e1f62020-10-23 16:13:57 -04001193 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), 2*kImageWH,
1194 /*hits*/ 2, /*misses*/ 2, /*refs*/ 2, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001195
1196 dContext->flush();
1197 dContext->submit(true);
1198
1199 // This should clear out everything but the textures locked in the thread-safe cache
1200 dContext->purgeUnlockedResources(false);
1201
1202 ddl1 = nullptr;
1203 ddl2 = nullptr;
1204
1205 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
Robert Phillips375e1f62020-10-23 16:13:57 -04001206 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
1207 /*hits*/ 2, /*misses*/ 2, /*refs*/ 0, kNoID));
1208 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH,
1209 /*hits*/ 2, /*misses*/ 2, /*refs*/ 0, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001210
1211 // Regardless of which image is MRU, this should force the other out
1212 size_t desiredBytes = helper.gpuSize(2*kImageWH) + helper.gpuSize(kImageWH)/2;
1213
1214 auto cache = dContext->priv().getResourceCache();
1215 size_t currentBytes = cache->getResourceBytes();
1216
1217 SkASSERT(currentBytes >= desiredBytes);
1218 size_t amountToPurge = currentBytes - desiredBytes;
1219
1220 // The 2*kImageWH texture should be MRU.
1221 dContext->purgeUnlockedResources(amountToPurge, true);
1222
1223 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
1224
Robert Phillips375e1f62020-10-23 16:13:57 -04001225 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH,
1226 /*hits*/ 2, /*misses*/ 2, /*refs*/ 0, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001227}
Robert Phillips331699c2020-09-22 15:20:01 -04001228
Brian Salomonb8c4add2021-06-28 09:20:44 -04001229DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache10View, reporter, ctxInfo) {
1230 test_10(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
Robert Phillips375e1f62020-10-23 16:13:57 -04001231}
1232
1233// To enable test_10 with verts would require a bit more work, namely:
1234// have a different # of verts based on size
1235// also pass in a gpuSize function to 'test_10'
1236//DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache10Verts, reporter, ctxInfo) {
1237// test_10(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
1238//}
1239
Robert Phillips331699c2020-09-22 15:20:01 -04001240// Case 11: This checks that scratch-only variant of GrContext::purgeUnlockedResources works as
Robert Phillipsdefd2232020-09-25 15:25:46 -04001241// expected wrt the thread safe cache. In particular, that when 'scratchResourcesOnly'
1242// is true, the call has no effect on the cache.
Robert Phillips375e1f62020-10-23 16:13:57 -04001243static void test_11(GrDirectContext* dContext, skiatest::Reporter* reporter,
1244 TestHelper::addAccessFP addAccess,
1245 TestHelper::checkFP check) {
Robert Phillips331699c2020-09-22 15:20:01 -04001246
1247 TestHelper helper(dContext);
1248
Robert Phillips375e1f62020-10-23 16:13:57 -04001249 (helper.*addAccess)(helper.liveCanvas(), kImageWH, kNoID, false, false);
1250 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
1251 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
Robert Phillips331699c2020-09-22 15:20:01 -04001252
Robert Phillips375e1f62020-10-23 16:13:57 -04001253 (helper.*addAccess)(helper.liveCanvas(), 2*kImageWH, kNoID, false, false);
1254 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH,
1255 /*hits*/ 0, /*misses*/ 2, /*refs*/ 1, kNoID));
Robert Phillips331699c2020-09-22 15:20:01 -04001256
1257 dContext->flush();
1258 dContext->submit(true);
1259
1260 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
Robert Phillips375e1f62020-10-23 16:13:57 -04001261 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
1262 /*hits*/ 0, /*misses*/ 2, /*refs*/ 0, kNoID));
1263 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH,
1264 /*hits*/ 0, /*misses*/ 2, /*refs*/ 0, kNoID));
Robert Phillips331699c2020-09-22 15:20:01 -04001265
1266 // This shouldn't remove anything from the cache
1267 dContext->purgeUnlockedResources(/* scratchResourcesOnly */ true);
1268
1269 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
1270
1271 dContext->purgeUnlockedResources(/* scratchResourcesOnly */ false);
1272
1273 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0);
1274}
1275
Robert Phillips375e1f62020-10-23 16:13:57 -04001276DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache11View, reporter, ctxInfo) {
1277 test_11(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
1278}
1279
1280DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache11Verts, reporter, ctxInfo) {
1281 test_11(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
1282}
1283
Robert Phillipsdefd2232020-09-25 15:25:46 -04001284// Case 12: Test out purges caused by resetting the cache budget to 0. Note that, due to
1285// the how the cache operates (i.e., not directly driven by ref/unrefs) there
1286// needs to be an explicit kick to purge the cache.
Robert Phillips375e1f62020-10-23 16:13:57 -04001287static void test_12(GrDirectContext* dContext, skiatest::Reporter* reporter,
1288 TestHelper::addAccessFP addAccess,
1289 TestHelper::checkFP check) {
Robert Phillips331699c2020-09-22 15:20:01 -04001290
1291 TestHelper helper(dContext);
1292
Robert Phillips375e1f62020-10-23 16:13:57 -04001293 (helper.*addAccess)(helper.liveCanvas(), kImageWH, kNoID, false, false);
1294 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
1295 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
1296 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false);
Robert Phillips331699c2020-09-22 15:20:01 -04001297 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
Robert Phillips375e1f62020-10-23 16:13:57 -04001298 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
1299 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, kNoID));
Robert Phillips331699c2020-09-22 15:20:01 -04001300
Robert Phillips375e1f62020-10-23 16:13:57 -04001301 (helper.*addAccess)(helper.liveCanvas(), 2*kImageWH, kNoID, false, false);
1302 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH,
1303 /*hits*/ 1, /*misses*/ 2, /*refs*/ 1, kNoID));
Robert Phillips331699c2020-09-22 15:20:01 -04001304
1305 dContext->flush();
1306 dContext->submit(true);
1307
1308 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
Robert Phillips375e1f62020-10-23 16:13:57 -04001309 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
1310 /*hits*/ 1, /*misses*/ 2, /*refs*/ 1, kNoID));
1311 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH,
1312 /*hits*/ 1, /*misses*/ 2, /*refs*/ 0, kNoID));
Robert Phillips331699c2020-09-22 15:20:01 -04001313
1314 dContext->setResourceCacheLimit(0);
1315
1316 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
1317
1318 ddl1 = nullptr;
1319
Robert Phillipsdefd2232020-09-25 15:25:46 -04001320 // Explicitly kick off the purge - it won't happen automatically on unref
Robert Phillips331699c2020-09-22 15:20:01 -04001321 dContext->performDeferredCleanup(std::chrono::milliseconds(0));
1322
1323 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0);
1324}
Robert Phillipsc2fe1642020-09-22 17:34:51 -04001325
Robert Phillips375e1f62020-10-23 16:13:57 -04001326DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache12View, reporter, ctxInfo) {
1327 test_12(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
1328}
1329
1330DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache12Verts, reporter, ctxInfo) {
1331 test_12(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
1332}
1333
Robert Phillipsc2fe1642020-09-22 17:34:51 -04001334// Case 13: Test out the 'msNotUsed' parameter to GrContext::performDeferredCleanup.
Robert Phillips375e1f62020-10-23 16:13:57 -04001335static void test_13(GrDirectContext* dContext, skiatest::Reporter* reporter,
1336 TestHelper::addAccessFP addAccess,
1337 TestHelper::checkFP check) {
Robert Phillipsc2fe1642020-09-22 17:34:51 -04001338
1339 TestHelper helper(dContext);
1340
Robert Phillips375e1f62020-10-23 16:13:57 -04001341 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false);
1342 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
1343 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
Robert Phillipsc2fe1642020-09-22 17:34:51 -04001344 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
1345
1346 std::this_thread::sleep_for(std::chrono::milliseconds(5));
1347 auto firstTime = GrStdSteadyClock::now();
1348 std::this_thread::sleep_for(std::chrono::milliseconds(5));
1349
Robert Phillips375e1f62020-10-23 16:13:57 -04001350 (helper.*addAccess)(helper.ddlCanvas2(), 2*kImageWH, kNoID, false, false);
1351
1352 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), 2*kImageWH,
1353 /*hits*/ 0, /*misses*/ 2, /*refs*/ 1, kNoID));
Robert Phillipsc2fe1642020-09-22 17:34:51 -04001354 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
1355
1356 ddl1 = nullptr;
1357 ddl2 = nullptr;
1358
1359 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
1360
1361 auto secondTime = GrStdSteadyClock::now();
1362
1363 auto msecs = std::chrono::duration_cast<std::chrono::milliseconds>(secondTime - firstTime);
1364 dContext->performDeferredCleanup(msecs);
1365
1366 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips375e1f62020-10-23 16:13:57 -04001367 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH,
1368 /*hits*/ 0, /*misses*/ 2, /*refs*/ 0, kNoID));
1369}
1370
1371DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache13View, reporter, ctxInfo) {
1372 test_13(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
1373}
1374
1375DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache13Verts, reporter, ctxInfo) {
1376 test_13(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
Robert Phillipsc2fe1642020-09-22 17:34:51 -04001377}
Robert Phillips3ac83b2f2020-10-26 13:50:57 -04001378
1379// Case 14: Test out mixing & matching view & vertex data w/ recycling of the cache entries to
1380// wring out the anonymous union code. This is mainly for the MSAN bot's consumption.
1381DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache14, reporter, ctxInfo) {
1382 constexpr int kBestPrimeNumber = 73; // palindromic in binary
1383 SkRandom rand(kBestPrimeNumber);
1384
1385 TestHelper helper(ctxInfo.directContext());
1386
1387 for (int i = 0; i < 2; ++i) {
1388 SkCanvas* ddlCanvas = (!i) ? helper.ddlCanvas1() : helper.ddlCanvas2();
1389
1390 for (int j = 0; j < 10; ++j) {
1391 int numResources = 10*i + j + 1;
1392 int wh = numResources;
1393
1394 if (rand.nextBool()) {
1395 helper.addViewAccess(ddlCanvas, wh, kNoID, false, false);
1396 REPORTER_ASSERT(reporter, helper.checkView(ddlCanvas, wh,
1397 /*hits*/ 0, /*misses*/ numResources,
1398 /*refs*/ 1, kNoID));
1399 } else {
1400 helper.addVertAccess(ddlCanvas, wh, kNoID, false, false);
1401 REPORTER_ASSERT(reporter, helper.checkVert(ddlCanvas, wh,
1402 /*hits*/ 0, /*misses*/ numResources,
1403 /*refs*/ 1, kNoID));
1404 }
1405 }
1406
1407 if (!i) {
1408 // Drop all the accumulated resources from the thread-safe cache
1409 helper.snap1();
1410 ctxInfo.directContext()->purgeUnlockedResources(/* scratchResourcesOnly */ false);
1411 }
1412 }
1413}
Robert Phillips83c38a82020-10-28 14:57:53 -04001414
1415// Case 15: Test out posting invalidation messages that involve the thread safe cache
1416static void test_15(GrDirectContext* dContext, skiatest::Reporter* reporter,
1417 TestHelper::addAccessFP addAccess,
1418 TestHelper::checkFP check,
1419 void (*create_key)(GrUniqueKey*, int wh, int id)) {
1420
1421 TestHelper helper(dContext);
1422
1423 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false);
1424 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
1425 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
1426 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
1427
1428 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
1429
1430 GrUniqueKey key;
1431 (*create_key)(&key, kImageWH, kNoID);
1432
1433 GrUniqueKeyInvalidatedMessage msg(key, dContext->priv().contextID(),
1434 /* inThreadSafeCache */ true);
1435
Robert Phillipse7a959d2021-03-11 14:44:42 -05001436 SkMessageBus<GrUniqueKeyInvalidatedMessage, uint32_t>::Post(msg);
Robert Phillips83c38a82020-10-28 14:57:53 -04001437
1438 // This purge call is needed to process the invalidation messages
1439 dContext->purgeUnlockedResources(/* scratchResourcesOnly */ true);
1440
1441 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0);
1442
1443 (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, kNoID, false, false);
1444 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), kImageWH,
1445 /*hits*/ 0, /*misses*/ 2, /*refs*/ 1, kNoID));
1446 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
1447
1448 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
1449
1450 helper.checkImage(reporter, std::move(ddl1));
1451 helper.checkImage(reporter, std::move(ddl2));
1452}
1453
1454DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache15View, reporter, ctxInfo) {
1455 test_15(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView,
1456 create_view_key);
1457}
1458
1459DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache15Verts, reporter, ctxInfo) {
1460 test_15(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert,
1461 create_vert_key);
1462}
Robert Phillips67e58cb2020-11-02 08:57:39 -05001463
1464// Case 16: Test out pre-emption of an existing vertex-data cache entry. This test simulates
1465// the case where there is a race to create vertex data. However, the second one
1466// to finish is better and usurps the first's position in the cache.
1467//
1468// This capability isn't available for views.
1469
1470static bool newer_is_always_better(SkData* /* incumbent */, SkData* /* challenger */) {
1471 return true;
1472};
1473
1474DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache16Verts, reporter, ctxInfo) {
1475 GrUniqueKey key;
1476 create_vert_key(&key, kImageWH, kNoID);
1477
1478 TestHelper helper(ctxInfo.directContext(), newer_is_always_better);
1479
1480 GrThreadSafeVertexTestOp* op1 = nullptr, *op2 = nullptr;
1481
1482 helper.addVertAccess(helper.ddlCanvas1(), kImageWH, kNoID, false, false, &op1);
1483 REPORTER_ASSERT(reporter, helper.checkVert(helper.ddlCanvas1(), kImageWH,
1484 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
1485 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
1486
1487 {
1488 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
1489 auto [vertexData, xtraData] = helper.threadSafeCache()->findVertsWithData(key);
1490 REPORTER_ASSERT(reporter, vertexData.get() == op1->vertexData());
1491 }
1492
1493 helper.addVertAccess(helper.ddlCanvas2(), kImageWH, kNoID, /* failLookup */ true, false, &op2);
1494 REPORTER_ASSERT(reporter, helper.checkVert(helper.ddlCanvas2(), kImageWH,
1495 /*hits*/ 0, /*misses*/ 2, /*refs*/ 1, kNoID));
1496 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
1497
1498 REPORTER_ASSERT(reporter, op1->vertexData() != op2->vertexData());
1499
1500 {
1501 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
1502 auto [vertexData, xtraData] = helper.threadSafeCache()->findVertsWithData(key);
1503 REPORTER_ASSERT(reporter, vertexData.get() == op2->vertexData());
1504 }
1505
1506 helper.checkImage(reporter, std::move(ddl1));
1507 helper.checkImage(reporter, std::move(ddl2));
1508}