blob: b5e47f0b57ab79fcaccf2beb1ec4ce8419034232 [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 Phillips06273bc2021-08-11 15:43:50 -040025#include "src/gpu/ops/GrDrawOp.h"
Robert Phillips4dca8312021-07-28 15:13:20 -040026#include "src/gpu/v1/SurfaceDrawContext_v1.h"
Robert Phillips26f3aeb2020-09-16 10:57:32 -040027#include "tests/Test.h"
28#include "tests/TestUtils.h"
Robert Phillips375e1f62020-10-23 16:13:57 -040029#include "tools/gpu/ProxyUtils.h"
Robert Phillips26f3aeb2020-09-16 10:57:32 -040030
Robert Phillipsc2fe1642020-09-22 17:34:51 -040031#include <thread>
32
Robert Phillips26f3aeb2020-09-16 10:57:32 -040033static constexpr int kImageWH = 32;
34static constexpr auto kImageOrigin = kBottomLeft_GrSurfaceOrigin;
Robert Phillips6e17ffe2020-10-06 14:52:11 -040035static constexpr int kNoID = -1;
Robert Phillips26f3aeb2020-09-16 10:57:32 -040036
37static SkImageInfo default_ii(int wh) {
38 return SkImageInfo::Make(wh, wh, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
39}
40
Robert Phillips4dca8312021-07-28 15:13:20 -040041static std::unique_ptr<skgpu::v1::SurfaceDrawContext> new_SDC(GrRecordingContext* rContext,
42 int wh) {
43 return skgpu::v1::SurfaceDrawContext::Make(rContext,
44 GrColorType::kRGBA_8888,
45 nullptr,
46 SkBackingFit::kExact,
47 {wh, wh},
48 SkSurfaceProps(),
49 1,
50 GrMipMapped::kNo,
51 GrProtected::kNo,
52 kImageOrigin,
53 SkBudgeted::kYes);
Robert Phillips3380be92020-09-25 12:47:10 -040054}
55
Robert Phillips375e1f62020-10-23 16:13:57 -040056static void create_view_key(GrUniqueKey* key, int wh, int id) {
57 static const GrUniqueKey::Domain kViewDomain = GrUniqueKey::GenerateDomain();
58 GrUniqueKey::Builder builder(key, kViewDomain, 1);
Robert Phillips26f3aeb2020-09-16 10:57:32 -040059 builder[0] = wh;
60 builder.finish();
Robert Phillips6e17ffe2020-10-06 14:52:11 -040061
62 if (id != kNoID) {
63 key->setCustomData(SkData::MakeWithCopy(&id, sizeof(id)));
64 }
Robert Phillips375e1f62020-10-23 16:13:57 -040065}
Robert Phillips26f3aeb2020-09-16 10:57:32 -040066
Robert Phillips375e1f62020-10-23 16:13:57 -040067static void create_vert_key(GrUniqueKey* key, int wh, int id) {
68 static const GrUniqueKey::Domain kVertDomain = GrUniqueKey::GenerateDomain();
69 GrUniqueKey::Builder builder(key, kVertDomain, 1);
70 builder[0] = wh;
71 builder.finish();
72
73 if (id != kNoID) {
74 key->setCustomData(SkData::MakeWithCopy(&id, sizeof(id)));
75 }
76}
77
Robert Phillips67e58cb2020-11-02 08:57:39 -050078static bool default_is_newer_better(SkData* incumbent, SkData* challenger) {
79 return false;
80}
81
Robert Phillips375e1f62020-10-23 16:13:57 -040082// When testing views we create a bitmap that covers the entire screen and has an inset blue rect
83// atop a field of white.
84// When testing verts we clear the background to white and simply draw an inset blur rect.
Robert Phillips3380be92020-09-25 12:47:10 -040085static SkBitmap create_bitmap(int wh) {
Robert Phillips26f3aeb2020-09-16 10:57:32 -040086 SkBitmap bitmap;
87
88 bitmap.allocPixels(default_ii(wh));
89
90 SkCanvas tmp(bitmap);
91 tmp.clear(SK_ColorWHITE);
92
93 SkPaint blue;
94 blue.setColor(SK_ColorBLUE);
Robert Phillips3380be92020-09-25 12:47:10 -040095 blue.setAntiAlias(false);
Robert Phillips26f3aeb2020-09-16 10:57:32 -040096
Robert Phillips3380be92020-09-25 12:47:10 -040097 tmp.drawRect({10, 10, wh-10.0f, wh-10.0f}, blue);
Robert Phillips26f3aeb2020-09-16 10:57:32 -040098
Robert Phillipsdefd2232020-09-25 15:25:46 -040099 bitmap.setImmutable();
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400100 return bitmap;
101}
102
Robert Phillips67e58cb2020-11-02 08:57:39 -0500103class GrThreadSafeVertexTestOp;
104
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400105class TestHelper {
106public:
107 struct Stats {
108 int fCacheHits = 0;
109 int fCacheMisses = 0;
110
111 int fNumSWCreations = 0;
Robert Phillips3380be92020-09-25 12:47:10 -0400112 int fNumLazyCreations = 0;
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400113 int fNumHWCreations = 0;
114 };
115
Robert Phillips67e58cb2020-11-02 08:57:39 -0500116 TestHelper(GrDirectContext* dContext,
117 GrThreadSafeCache::IsNewerBetter isNewerBetter = default_is_newer_better)
118 : fDContext(dContext)
119 , fIsNewerBetter(isNewerBetter) {
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400120
121 fDst = SkSurface::MakeRenderTarget(dContext, SkBudgeted::kNo, default_ii(kImageWH));
122 SkAssertResult(fDst);
123
124 SkSurfaceCharacterization characterization;
125 SkAssertResult(fDst->characterize(&characterization));
126
127 fRecorder1 = std::make_unique<SkDeferredDisplayListRecorder>(characterization);
Robert Phillips375e1f62020-10-23 16:13:57 -0400128 this->ddlCanvas1()->clear(SkColors::kWhite);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400129
130 fRecorder2 = std::make_unique<SkDeferredDisplayListRecorder>(characterization);
Robert Phillips375e1f62020-10-23 16:13:57 -0400131 this->ddlCanvas2()->clear(SkColors::kWhite);
132
133 fDst->getCanvas()->clear(SkColors::kWhite);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400134 }
135
136 ~TestHelper() {
Robert Phillips187b04b2020-09-22 12:18:16 -0400137 fDContext->flush();
138 fDContext->submit(true);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400139 }
140
141 Stats* stats() { return &fStats; }
142
Robert Phillipsd464feb2020-10-08 11:00:02 -0400143 int numCacheEntries() const { return this->threadSafeCache()->numEntries(); }
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400144
145 GrDirectContext* dContext() { return fDContext; }
146
147 SkCanvas* liveCanvas() { return fDst ? fDst->getCanvas() : nullptr; }
148 SkCanvas* ddlCanvas1() { return fRecorder1 ? fRecorder1->getCanvas() : nullptr; }
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400149 sk_sp<SkDeferredDisplayList> snap1() {
150 if (fRecorder1) {
151 sk_sp<SkDeferredDisplayList> tmp = fRecorder1->detach();
152 fRecorder1 = nullptr;
153 return tmp;
154 }
155
156 return nullptr;
157 }
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400158 SkCanvas* ddlCanvas2() { return fRecorder2 ? fRecorder2->getCanvas() : nullptr; }
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400159 sk_sp<SkDeferredDisplayList> snap2() {
160 if (fRecorder2) {
161 sk_sp<SkDeferredDisplayList> tmp = fRecorder2->detach();
162 fRecorder2 = nullptr;
163 return tmp;
164 }
165
166 return nullptr;
167 }
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400168
Robert Phillipsd464feb2020-10-08 11:00:02 -0400169 GrThreadSafeCache* threadSafeCache() { return fDContext->priv().threadSafeCache(); }
170 const GrThreadSafeCache* threadSafeCache() const { return fDContext->priv().threadSafeCache(); }
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400171
Robert Phillips375e1f62020-10-23 16:13:57 -0400172 typedef void (TestHelper::*addAccessFP)(SkCanvas*, int wh, int id,
173 bool failLookUp, bool failFillingIn);
174 typedef bool (TestHelper::*checkFP)(SkCanvas*, int wh,
175 int expectedHits, int expectedMisses,
176 int expectedNumRefs, int expectedID);
177
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400178 // Add a draw on 'canvas' that will introduce a ref on the 'wh' view
Robert Phillips375e1f62020-10-23 16:13:57 -0400179 void addViewAccess(SkCanvas* canvas,
180 int wh,
181 int id = kNoID,
182 bool failLookup = false,
183 bool failFillingIn = false) {
184 auto rContext = canvas->recordingContext();
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400185
Robert Phillipsd464feb2020-10-08 11:00:02 -0400186 auto view = AccessCachedView(rContext, this->threadSafeCache(),
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400187 wh, failLookup, failFillingIn, id, &fStats);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400188 SkASSERT(view);
189
Brian Salomon8f7d9532020-12-23 09:16:59 -0500190 auto sdc = SkCanvasPriv::TopDeviceSurfaceDrawContext(canvas);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400191
Brian Salomon8f7d9532020-12-23 09:16:59 -0500192 sdc->drawTexture(nullptr,
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400193 view,
194 kPremul_SkAlphaType,
195 GrSamplerState::Filter::kNearest,
196 GrSamplerState::MipmapMode::kNone,
197 SkBlendMode::kSrcOver,
Robert Phillipsdefd2232020-09-25 15:25:46 -0400198 {1.0f, 1.0f, 1.0f, 1.0f},
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400199 SkRect::MakeWH(wh, wh),
200 SkRect::MakeWH(wh, wh),
201 GrAA::kNo,
202 GrQuadAAFlags::kNone,
203 SkCanvas::kFast_SrcRectConstraint,
204 SkMatrix::I(),
205 nullptr);
206 }
207
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400208 // Besides checking that the number of refs and cache hits and misses are as expected, this
209 // method also validates that the unique key doesn't appear in any of the other caches.
Robert Phillips375e1f62020-10-23 16:13:57 -0400210 bool checkView(SkCanvas* canvas, int wh,
211 int expectedHits, int expectedMisses, int expectedNumRefs, int expectedID) {
212 if (fStats.fCacheHits != expectedHits || fStats.fCacheMisses != expectedMisses) {
Robert Phillips187b04b2020-09-22 12:18:16 -0400213 SkDebugf("Hits E: %d A: %d --- Misses E: %d A: %d\n",
Robert Phillips375e1f62020-10-23 16:13:57 -0400214 expectedHits, fStats.fCacheHits, expectedMisses, fStats.fCacheMisses);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400215 return false;
216 }
217
218 GrUniqueKey key;
Robert Phillips375e1f62020-10-23 16:13:57 -0400219 create_view_key(&key, wh, kNoID);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400220
Robert Phillipsd464feb2020-10-08 11:00:02 -0400221 auto threadSafeCache = this->threadSafeCache();
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400222
Robert Phillips375e1f62020-10-23 16:13:57 -0400223 auto [view, xtraData] = threadSafeCache->findWithData(key);
Robert Phillips187b04b2020-09-22 12:18:16 -0400224 if (!view.proxy()) {
225 return false;
226 }
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400227
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400228 if (expectedID < 0) {
Robert Phillips375e1f62020-10-23 16:13:57 -0400229 if (xtraData) {
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400230 return false;
231 }
232 } else {
Robert Phillips375e1f62020-10-23 16:13:57 -0400233 if (!xtraData) {
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400234 return false;
235 }
236
Robert Phillips375e1f62020-10-23 16:13:57 -0400237 const int* cachedID = static_cast<const int*>(xtraData->data());
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400238 if (*cachedID != expectedID) {
239 return false;
240 }
241 }
242
Robert Phillips375e1f62020-10-23 16:13:57 -0400243 if (!view.proxy()->refCntGreaterThan(expectedNumRefs+1) || // +1 for 'view's ref
244 view.proxy()->refCntGreaterThan(expectedNumRefs+2)) {
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400245 return false;
246 }
247
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400248 if (canvas) {
249 GrRecordingContext* rContext = canvas->recordingContext();
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400250 GrProxyProvider* recordingProxyProvider = rContext->priv().proxyProvider();
251 sk_sp<GrTextureProxy> result = recordingProxyProvider->findProxyByUniqueKey(key);
252 if (result) {
253 // views in this cache should never appear in the recorder's cache
254 return false;
255 }
256 }
257
258 {
259 GrProxyProvider* directProxyProvider = fDContext->priv().proxyProvider();
260 sk_sp<GrTextureProxy> result = directProxyProvider->findProxyByUniqueKey(key);
261 if (result) {
262 // views in this cache should never appear in the main proxy cache
263 return false;
264 }
265 }
266
267 {
268 auto resourceProvider = fDContext->priv().resourceProvider();
269 sk_sp<GrSurface> surf = resourceProvider->findByUniqueKey<GrSurface>(key);
270 if (surf) {
271 // the textures backing the views in this cache should never be discoverable in the
272 // resource cache
273 return false;
274 }
275 }
276
277 return true;
278 }
279
Robert Phillips67e58cb2020-11-02 08:57:39 -0500280 void addVertAccess(SkCanvas* canvas,
281 int wh,
282 int id,
283 bool failLookup,
284 bool failFillingIn,
285 GrThreadSafeVertexTestOp** createdOp);
286
Robert Phillips375e1f62020-10-23 16:13:57 -0400287 // Add a draw on 'canvas' that will introduce a ref on a 'wh' vertex data
288 void addVertAccess(SkCanvas* canvas,
289 int wh,
290 int id = kNoID,
291 bool failLookup = false,
Robert Phillips67e58cb2020-11-02 08:57:39 -0500292 bool failFillingIn = false) {
293 this->addVertAccess(canvas, wh, id, failLookup, failFillingIn, nullptr);
294 }
Robert Phillips375e1f62020-10-23 16:13:57 -0400295
296 bool checkVert(SkCanvas* canvas, int wh,
297 int expectedHits, int expectedMisses, int expectedNumRefs, int expectedID) {
298 if (fStats.fCacheHits != expectedHits || fStats.fCacheMisses != expectedMisses) {
299 SkDebugf("Hits E: %d A: %d --- Misses E: %d A: %d\n",
300 expectedHits, fStats.fCacheHits, expectedMisses, fStats.fCacheMisses);
301 return false;
302 }
303
304 GrUniqueKey key;
305 create_vert_key(&key, wh, kNoID);
306
307 auto threadSafeCache = this->threadSafeCache();
308
309 auto [vertData, xtraData] = threadSafeCache->findVertsWithData(key);
310 if (!vertData) {
311 return false;
312 }
313
314 if (expectedID < 0) {
315 if (xtraData) {
316 return false;
317 }
318 } else {
319 if (!xtraData) {
320 return false;
321 }
322
323 const int* cachedID = static_cast<const int*>(xtraData->data());
324 if (*cachedID != expectedID) {
325 return false;
326 }
327 }
328
329 if (!vertData->refCntGreaterThan(expectedNumRefs+1) || // +1 for 'vertData's ref
330 vertData->refCntGreaterThan(expectedNumRefs+2)) {
331 return false;
332 }
333
334 {
335 auto resourceProvider = fDContext->priv().resourceProvider();
336 sk_sp<GrGpuBuffer> buffer = resourceProvider->findByUniqueKey<GrGpuBuffer>(key);
337 if (buffer) {
338 // the buffer holding the vertex data in this cache should never be discoverable
339 // in the resource cache
340 return false;
341 }
342 }
343
344 return true;
345 }
346
Robert Phillipsdefd2232020-09-25 15:25:46 -0400347 bool checkImage(skiatest::Reporter* reporter, sk_sp<SkSurface> s) {
348 SkBitmap actual;
349
350 actual.allocPixels(default_ii(kImageWH));
351
352 if (!s->readPixels(actual, 0, 0)) {
353 return false;
354 }
355
356 SkBitmap expected = create_bitmap(kImageWH);
357
358 const float tols[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
359
360 auto error = std::function<ComparePixmapsErrorReporter>(
361 [reporter](int x, int y, const float diffs[4]) {
362 SkASSERT(x >= 0 && y >= 0);
363 ERRORF(reporter, "mismatch at %d, %d (%f, %f, %f %f)",
364 x, y, diffs[0], diffs[1], diffs[2], diffs[3]);
365 });
366
367 return ComparePixels(expected.pixmap(), actual.pixmap(), tols, error);
368 }
369
370 bool checkImage(skiatest::Reporter* reporter) {
371 return this->checkImage(reporter, fDst);
372 }
373
374 bool checkImage(skiatest::Reporter* reporter, sk_sp<SkDeferredDisplayList> ddl) {
375 sk_sp<SkSurface> tmp = SkSurface::MakeRenderTarget(fDContext,
376 SkBudgeted::kNo,
377 default_ii(kImageWH));
378 if (!tmp) {
379 return false;
380 }
381
382 if (!tmp->draw(std::move(ddl))) {
383 return false;
384 }
385
386 return this->checkImage(reporter, std::move(tmp));
387 }
388
Robert Phillips187b04b2020-09-22 12:18:16 -0400389 size_t gpuSize(int wh) const {
390 GrBackendFormat format = fDContext->defaultBackendFormat(kRGBA_8888_SkColorType,
391 GrRenderable::kNo);
392
Greg Daniel0eca74c2020-10-01 13:46:00 -0400393 return GrSurface::ComputeSize(format, {wh, wh}, /*colorSamplesPerPixel=*/1,
394 GrMipMapped::kNo, /*binSize=*/false);
Robert Phillips187b04b2020-09-22 12:18:16 -0400395 }
396
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400397private:
398 static GrSurfaceProxyView AccessCachedView(GrRecordingContext*,
Robert Phillipsd464feb2020-10-08 11:00:02 -0400399 GrThreadSafeCache*,
Robert Phillips187b04b2020-09-22 12:18:16 -0400400 int wh,
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400401 bool failLookup, bool failFillingIn, int id,
Robert Phillips3380be92020-09-25 12:47:10 -0400402 Stats*);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400403 static GrSurfaceProxyView CreateViewOnCpu(GrRecordingContext*, int wh, Stats*);
Robert Phillips3380be92020-09-25 12:47:10 -0400404 static bool FillInViewOnGpu(GrDirectContext*, int wh, Stats*,
405 const GrSurfaceProxyView& lazyView,
Robert Phillipsd464feb2020-10-08 11:00:02 -0400406 sk_sp<GrThreadSafeCache::Trampoline>);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400407
408 Stats fStats;
409 GrDirectContext* fDContext = nullptr;
Robert Phillips67e58cb2020-11-02 08:57:39 -0500410 GrThreadSafeCache::IsNewerBetter fIsNewerBetter;
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400411
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400412 sk_sp<SkSurface> fDst;
413 std::unique_ptr<SkDeferredDisplayListRecorder> fRecorder1;
414 std::unique_ptr<SkDeferredDisplayListRecorder> fRecorder2;
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400415};
416
Robert Phillips375e1f62020-10-23 16:13:57 -0400417class GrThreadSafeVertexTestOp : public GrDrawOp {
418public:
419 DEFINE_OP_CLASS_ID
420
Herb Derbyc76d4092020-10-07 16:46:15 -0400421 static GrOp::Owner Make(GrRecordingContext* rContext, TestHelper::Stats* stats,
Robert Phillips67e58cb2020-11-02 08:57:39 -0500422 int wh, int id, bool failLookup, bool failFillingIn,
423 GrThreadSafeCache::IsNewerBetter isNewerBetter) {
Robert Phillips375e1f62020-10-23 16:13:57 -0400424
Herb Derbyc76d4092020-10-07 16:46:15 -0400425 return GrOp::Make<GrThreadSafeVertexTestOp>(
Robert Phillips67e58cb2020-11-02 08:57:39 -0500426 rContext, rContext, stats, wh, id, failLookup, failFillingIn, isNewerBetter);
Robert Phillips375e1f62020-10-23 16:13:57 -0400427 }
428
Robert Phillips67e58cb2020-11-02 08:57:39 -0500429 const GrThreadSafeCache::VertexData* vertexData() const { return fVertexData.get(); }
430
Robert Phillips375e1f62020-10-23 16:13:57 -0400431private:
Herb Derbyc76d4092020-10-07 16:46:15 -0400432 friend class GrOp; // for ctor
Robert Phillips375e1f62020-10-23 16:13:57 -0400433
434 GrThreadSafeVertexTestOp(GrRecordingContext* rContext, TestHelper::Stats* stats, int wh, int id,
Robert Phillips67e58cb2020-11-02 08:57:39 -0500435 bool failLookup, bool failFillingIn,
436 GrThreadSafeCache::IsNewerBetter isNewerBetter)
Robert Phillips375e1f62020-10-23 16:13:57 -0400437 : INHERITED(ClassID())
438 , fStats(stats)
439 , fWH(wh)
440 , fID(id)
Robert Phillips67e58cb2020-11-02 08:57:39 -0500441 , fFailFillingIn(failFillingIn)
442 , fIsNewerBetter(isNewerBetter) {
Robert Phillips375e1f62020-10-23 16:13:57 -0400443 this->setBounds(SkRect::MakeIWH(fWH, fWH), HasAABloat::kNo, IsHairline::kNo);
444
445 // Normally we wouldn't add a ref to the vertex data at this point. However, it is
446 // needed in this unit test to get the ref counts on the uniquely keyed resources
447 // to be as expected.
448 this->findOrCreateVertices(rContext, failLookup, fFailFillingIn);
449 }
450
451 const char* name() const override { return "GrThreadSafeVertexTestOp"; }
452 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
Chris Dalton57ab06c2021-04-22 12:57:28 -0600453 GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override {
Robert Phillips375e1f62020-10-23 16:13:57 -0400454 return GrProcessorSet::EmptySetAnalysis();
455 }
456
457 GrProgramInfo* createProgramInfo(const GrCaps* caps,
458 SkArenaAlloc* arena,
Adlai Hollere2296f72020-11-19 13:41:26 -0500459 const GrSurfaceProxyView& writeView,
Chris Dalton2a26c502021-08-26 10:05:11 -0600460 bool usesMSAASurface,
Robert Phillips375e1f62020-10-23 16:13:57 -0400461 GrAppliedClip&& appliedClip,
John Stiles52cb1d02021-06-02 11:58:05 -0400462 const GrDstProxyView& dstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -0500463 GrXferBarrierFlags renderPassXferBarriers,
464 GrLoadOp colorLoadOp) const {
Robert Phillips375e1f62020-10-23 16:13:57 -0400465 using namespace GrDefaultGeoProcFactory;
466
467 Color color({ 0.0f, 0.0f, 1.0f, 1.0f });
468
469 auto gp = MakeForDeviceSpace(arena, color,
470 Coverage::kSolid_Type,
471 LocalCoords::kUnused_Type,
472 SkMatrix::I());
473
Chris Dalton2a26c502021-08-26 10:05:11 -0600474 return sk_gpu_test::CreateProgramInfo(caps, arena, writeView, usesMSAASurface,
Robert Phillips375e1f62020-10-23 16:13:57 -0400475 std::move(appliedClip), dstProxyView,
476 gp, SkBlendMode::kSrcOver,
477 GrPrimitiveType::kTriangleStrip,
Greg Daniel42dbca52020-11-20 10:22:43 -0500478 renderPassXferBarriers, colorLoadOp);
Robert Phillips375e1f62020-10-23 16:13:57 -0400479 }
480
481 GrProgramInfo* createProgramInfo(GrOpFlushState* flushState) const {
482 return this->createProgramInfo(&flushState->caps(),
483 flushState->allocator(),
484 flushState->writeView(),
Chris Dalton2a26c502021-08-26 10:05:11 -0600485 flushState->usesMSAASurface(),
Robert Phillips375e1f62020-10-23 16:13:57 -0400486 flushState->detachAppliedClip(),
487 flushState->dstProxyView(),
Greg Daniel42dbca52020-11-20 10:22:43 -0500488 flushState->renderPassBarriers(),
489 flushState->colorLoadOp());
Robert Phillips375e1f62020-10-23 16:13:57 -0400490 }
491
492 void findOrCreateVertices(GrRecordingContext* rContext, bool failLookup, bool failFillingIn) {
493
494 if (!fVertexData) {
495 auto threadSafeViewCache = rContext->priv().threadSafeCache();
496
497 if (rContext->asDirectContext()) {
498 // The vertex variant doesn't have a correlate to lazyProxies but increment this
499 // here to make the unit tests happy.
500 ++fStats->fNumLazyCreations;
501 }
502
503 GrUniqueKey key;
504 create_vert_key(&key, fWH, fID);
505
506 // We can "fail the lookup" to simulate a threaded race condition
507 auto [cachedVerts, data] = threadSafeViewCache->findVertsWithData(key);
508 if (cachedVerts && !failLookup) {
509 fVertexData = cachedVerts;
510 ++fStats->fCacheHits;
511 return;
512 }
513
514 ++fStats->fCacheMisses;
515 if (!rContext->asDirectContext()) {
516 ++fStats->fNumSWCreations;
517 }
518
519 constexpr size_t kVertSize = sizeof(SkPoint);
520 SkPoint* verts = static_cast<SkPoint*>(sk_malloc_throw(4 * kVertSize));
521
522 verts[0].set(10.0f, 10.0f);
523 verts[1].set(fWH-10.0f, 10.0f);
524 verts[2].set(10.0f, fWH-10.0f);
525 verts[3].set(fWH-10.0f, fWH-10.0f);
526
527 fVertexData = GrThreadSafeCache::MakeVertexData(verts, 4, kVertSize);
528
Robert Phillips67e58cb2020-11-02 08:57:39 -0500529 auto [tmpV, tmpD] = threadSafeViewCache->addVertsWithData(key, fVertexData,
530 fIsNewerBetter);
Robert Phillips375e1f62020-10-23 16:13:57 -0400531 if (tmpV != fVertexData) {
532 // Someone beat us to creating the vertex data. Use that version.
533 fVertexData = tmpV;
534 }
535 }
536
537 if (auto dContext = rContext->asDirectContext(); dContext && !fVertexData->gpuBuffer()) {
538 auto rp = dContext->priv().resourceProvider();
539
540 if (!failFillingIn) {
541 ++fStats->fNumHWCreations;
542
543 sk_sp<GrGpuBuffer> tmp = rp->createBuffer(fVertexData->size(),
544 GrGpuBufferType::kVertex,
545 kStatic_GrAccessPattern,
546 fVertexData->vertices());
547 fVertexData->setGpuBuffer(std::move(tmp));
548 }
549 }
550 }
551
552 void onPrePrepare(GrRecordingContext* rContext,
Adlai Hollere2296f72020-11-19 13:41:26 -0500553 const GrSurfaceProxyView& writeView,
Robert Phillips375e1f62020-10-23 16:13:57 -0400554 GrAppliedClip* clip,
John Stiles52cb1d02021-06-02 11:58:05 -0400555 const GrDstProxyView& dstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -0500556 GrXferBarrierFlags renderPassXferBarriers,
557 GrLoadOp colorLoadOp) override {
Robert Phillips375e1f62020-10-23 16:13:57 -0400558 SkArenaAlloc* arena = rContext->priv().recordTimeAllocator();
559
Chris Dalton2a26c502021-08-26 10:05:11 -0600560 // DMSAA is not supported on DDL.
561 bool usesMSAASurface = writeView.asRenderTargetProxy()->numSamples() > 1;
562
Robert Phillips375e1f62020-10-23 16:13:57 -0400563 // This is equivalent to a GrOpFlushState::detachAppliedClip
564 GrAppliedClip appliedClip = clip ? std::move(*clip) : GrAppliedClip::Disabled();
565
566 fProgramInfo = this->createProgramInfo(rContext->priv().caps(), arena, writeView,
Chris Dalton2a26c502021-08-26 10:05:11 -0600567 usesMSAASurface, std::move(appliedClip),
568 dstProxyView, renderPassXferBarriers, colorLoadOp);
Robert Phillips375e1f62020-10-23 16:13:57 -0400569
570 rContext->priv().recordProgramInfo(fProgramInfo);
571
572 // This is now a noop (bc it is always called in the ctor) but is where we would normally
573 // create the vertices.
574 this->findOrCreateVertices(rContext, false, fFailFillingIn);
575 }
576
577 void onPrepare(GrOpFlushState* flushState) override {
578 auto dContext = flushState->gpu()->getContext();
579
580 // This call site is not a noop bc this op could've been created on with DDL context
581 // and, therefore, could be lacking a gpu-side buffer
582 this->findOrCreateVertices(dContext, false, fFailFillingIn);
583 }
584
585 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
586 if (!fVertexData || !fVertexData->gpuBuffer()) {
587 return;
588 }
589
590 if (!fProgramInfo) {
591 fProgramInfo = this->createProgramInfo(flushState);
592 }
593
594 flushState->bindPipeline(*fProgramInfo, SkRect::MakeIWH(fWH, fWH));
595 flushState->bindBuffers(nullptr, nullptr, fVertexData->refGpuBuffer());
596 flushState->draw(4, 0);
597 }
598
Robert Phillips67e58cb2020-11-02 08:57:39 -0500599 TestHelper::Stats* fStats;
600 int fWH;
601 int fID;
602 bool fFailFillingIn;
603 GrThreadSafeCache::IsNewerBetter fIsNewerBetter;
Robert Phillips375e1f62020-10-23 16:13:57 -0400604
605 sk_sp<GrThreadSafeCache::VertexData> fVertexData;
Robert Phillips67e58cb2020-11-02 08:57:39 -0500606 GrProgramInfo* fProgramInfo = nullptr;
Robert Phillips375e1f62020-10-23 16:13:57 -0400607
608 using INHERITED = GrDrawOp;
609};
610
611void TestHelper::addVertAccess(SkCanvas* canvas,
612 int wh, int id,
Robert Phillips67e58cb2020-11-02 08:57:39 -0500613 bool failLookup, bool failFillingIn,
614 GrThreadSafeVertexTestOp** createdOp) {
Robert Phillips375e1f62020-10-23 16:13:57 -0400615 auto rContext = canvas->recordingContext();
Brian Salomon8f7d9532020-12-23 09:16:59 -0500616 auto sdc = SkCanvasPriv::TopDeviceSurfaceDrawContext(canvas);
Robert Phillips375e1f62020-10-23 16:13:57 -0400617
Robert Phillips67e58cb2020-11-02 08:57:39 -0500618 GrOp::Owner op = GrThreadSafeVertexTestOp::Make(rContext, &fStats,
619 wh, id,
620 failLookup, failFillingIn,
621 fIsNewerBetter);
622 if (createdOp) {
623 *createdOp = (GrThreadSafeVertexTestOp*) op.get();
624 }
625
Brian Salomon8f7d9532020-12-23 09:16:59 -0500626 sdc->addDrawOp(std::move(op));
Robert Phillips375e1f62020-10-23 16:13:57 -0400627}
628
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400629GrSurfaceProxyView TestHelper::CreateViewOnCpu(GrRecordingContext* rContext,
630 int wh,
631 Stats* stats) {
632 GrProxyProvider* proxyProvider = rContext->priv().proxyProvider();
633
Robert Phillips3380be92020-09-25 12:47:10 -0400634 sk_sp<GrTextureProxy> proxy = proxyProvider->createProxyFromBitmap(create_bitmap(wh),
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400635 GrMipmapped::kNo,
636 SkBackingFit::kExact,
637 SkBudgeted::kYes);
638 if (!proxy) {
639 return {};
640 }
641
642 GrSwizzle swizzle = rContext->priv().caps()->getReadSwizzle(proxy->backendFormat(),
643 GrColorType::kRGBA_8888);
644 ++stats->fNumSWCreations;
645 return {std::move(proxy), kImageOrigin, swizzle};
646}
647
Robert Phillipsd464feb2020-10-08 11:00:02 -0400648bool TestHelper::FillInViewOnGpu(GrDirectContext* dContext, int wh, Stats* stats,
649 const GrSurfaceProxyView& lazyView,
650 sk_sp<GrThreadSafeCache::Trampoline> trampoline) {
Robert Phillips3380be92020-09-25 12:47:10 -0400651
Robert Phillips4dca8312021-07-28 15:13:20 -0400652 std::unique_ptr<skgpu::v1::SurfaceDrawContext> sdc = new_SDC(dContext, wh);
Robert Phillips3380be92020-09-25 12:47:10 -0400653
654 GrPaint paint;
655 paint.setColor4f({0.0f, 0.0f, 1.0f, 1.0f});
656
Robert Phillips4dca8312021-07-28 15:13:20 -0400657 sdc->clear(SkPMColor4f{1.0f, 1.0f, 1.0f, 1.0f});
658 sdc->drawRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(),
Robert Phillips3380be92020-09-25 12:47:10 -0400659 { 10, 10, wh-10.0f, wh-10.0f }, &GrStyle::SimpleFill());
660
661 ++stats->fNumHWCreations;
Robert Phillips4dca8312021-07-28 15:13:20 -0400662 auto view = sdc->readSurfaceView();
Robert Phillips3380be92020-09-25 12:47:10 -0400663
664 SkASSERT(view.swizzle() == lazyView.swizzle());
665 SkASSERT(view.origin() == lazyView.origin());
666 trampoline->fProxy = view.asTextureProxyRef();
667
668 return true;
669}
670
Robert Phillipsd464feb2020-10-08 11:00:02 -0400671GrSurfaceProxyView TestHelper::AccessCachedView(GrRecordingContext* rContext,
672 GrThreadSafeCache* threadSafeCache,
673 int wh,
674 bool failLookup, bool failFillingIn, int id,
675 Stats* stats) {
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400676 GrUniqueKey key;
Robert Phillips375e1f62020-10-23 16:13:57 -0400677 create_view_key(&key, wh, id);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400678
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400679 if (GrDirectContext* dContext = rContext->asDirectContext()) {
Robert Phillips3380be92020-09-25 12:47:10 -0400680 // The gpu thread gets priority over the recording threads. If the gpu thread is first,
681 // it crams a lazy proxy into the cache and then fills it in later.
Robert Phillipsd464feb2020-10-08 11:00:02 -0400682 auto [lazyView, trampoline] = GrThreadSafeCache::CreateLazyView(
Robert Phillipsfde67e42020-10-07 15:33:43 -0400683 dContext, GrColorType::kRGBA_8888, {wh, wh}, kImageOrigin, SkBackingFit::kExact);
Robert Phillipsb1807122020-10-06 16:44:18 -0400684 ++stats->fNumLazyCreations;
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400685
Robert Phillipsd464feb2020-10-08 11:00:02 -0400686 auto [view, data] = threadSafeCache->findOrAddWithData(key, lazyView);
Robert Phillips3380be92020-09-25 12:47:10 -0400687 if (view != lazyView) {
688 ++stats->fCacheHits;
689 return view;
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400690 } else if (id != kNoID) {
691 // Make sure, in this case, that the customData stuck
692 SkASSERT(data);
693 SkDEBUGCODE(const int* cachedID = static_cast<const int*>(data->data());)
694 SkASSERT(*cachedID == id);
Robert Phillips3380be92020-09-25 12:47:10 -0400695 }
696
697 ++stats->fCacheMisses;
698
699 if (failFillingIn) {
700 // Simulate something going horribly wrong at flush-time so no GrTexture is
701 // available to fulfill the lazy proxy.
702 return view;
703 }
704
705 if (!FillInViewOnGpu(dContext, wh, stats, lazyView, std::move(trampoline))) {
706 // In this case something has gone disastrously wrong so set up to drop the draw
707 // that needed this resource and reduce future pollution of the cache.
Robert Phillipsd464feb2020-10-08 11:00:02 -0400708 threadSafeCache->remove(key);
Robert Phillips3380be92020-09-25 12:47:10 -0400709 return {};
710 }
711
712 return view;
713 } else {
714 GrSurfaceProxyView view;
715
716 // We can "fail the lookup" to simulate a threaded race condition
Robert Phillipsd464feb2020-10-08 11:00:02 -0400717 if (view = threadSafeCache->find(key); !failLookup && view) {
Robert Phillips3380be92020-09-25 12:47:10 -0400718 ++stats->fCacheHits;
719 return view;
720 }
721
722 ++stats->fCacheMisses;
723
724 view = CreateViewOnCpu(rContext, wh, stats);
725 SkASSERT(view);
726
Robert Phillipsd464feb2020-10-08 11:00:02 -0400727 auto [newView, data] = threadSafeCache->addWithData(key, view);
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400728 if (view == newView && id != kNoID) {
729 // Make sure, in this case, that the customData stuck
730 SkASSERT(data);
731 SkDEBUGCODE(const int* cachedID = static_cast<const int*>(data->data());)
732 SkASSERT(*cachedID == id);
733 }
734 return newView;
Robert Phillips3380be92020-09-25 12:47:10 -0400735 }
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400736}
737
Robert Phillips375e1f62020-10-23 16:13:57 -0400738// Case 1: ensure two DDL recorders share the view/vertexData
739static void test_1(GrDirectContext* dContext, skiatest::Reporter* reporter,
740 TestHelper::addAccessFP addAccess,
741 TestHelper::checkFP check) {
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400742
Robert Phillips375e1f62020-10-23 16:13:57 -0400743 TestHelper helper(dContext);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400744
Robert Phillips375e1f62020-10-23 16:13:57 -0400745 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, 1, false, false);
746 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
747 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, /*id*/ 1));
748
749 (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, 2, false, false);
750 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), kImageWH,
751 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, /*id*/ 1));
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400752
753 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips3380be92020-09-25 12:47:10 -0400754 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 0);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400755 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 0);
756 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 1);
Robert Phillipsdefd2232020-09-25 15:25:46 -0400757
758 helper.checkImage(reporter, helper.snap1());
759 helper.checkImage(reporter, helper.snap2());
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400760}
761
Robert Phillips375e1f62020-10-23 16:13:57 -0400762DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache1View, reporter, ctxInfo) {
763 test_1(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
764}
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400765
Robert Phillips375e1f62020-10-23 16:13:57 -0400766DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache1Verts, reporter, ctxInfo) {
767 test_1(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
768}
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400769
Robert Phillips375e1f62020-10-23 16:13:57 -0400770// Case 2: ensure that, if the direct context version wins, its result is reused by the
771// DDL recorders
772static void test_2(GrDirectContext* dContext, skiatest::Reporter* reporter,
773 TestHelper::addAccessFP addAccess,
774 TestHelper::checkFP check) {
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400775
Robert Phillips375e1f62020-10-23 16:13:57 -0400776 TestHelper helper(dContext);
777
778 (helper.*addAccess)(helper.liveCanvas(), kImageWH, 1, false, false);
779 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
780 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, /*id*/ 1));
781
782 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, 2, false, false);
783 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
784 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, /*id*/ 1));
785
786 (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, 3, false, false);
787 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), kImageWH,
788 /*hits*/ 2, /*misses*/ 1, /*refs*/ 3, /*id*/ 1));
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400789
790 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips3380be92020-09-25 12:47:10 -0400791 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400792 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 1);
793 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0);
Robert Phillipsdefd2232020-09-25 15:25:46 -0400794
795 helper.checkImage(reporter);
796 helper.checkImage(reporter, helper.snap1());
797 helper.checkImage(reporter, helper.snap2());
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400798}
799
Robert Phillips375e1f62020-10-23 16:13:57 -0400800DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache2View, reporter, ctxInfo) {
801 test_2(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
802}
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400803
Robert Phillips375e1f62020-10-23 16:13:57 -0400804DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache2Verts, reporter, ctxInfo) {
805 test_2(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
806}
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400807
Robert Phillips375e1f62020-10-23 16:13:57 -0400808// Case 3: ensure that, if the cpu-version wins, its result is reused by the direct context
809static void test_3(GrDirectContext* dContext, skiatest::Reporter* reporter,
810 TestHelper::addAccessFP addAccess,
811 TestHelper::checkFP check) {
812
813 TestHelper helper(dContext);
814
815 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, 1, false, false);
816 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
817 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, /*id*/ 1));
818
819 (helper.*addAccess)(helper.liveCanvas(), kImageWH, 2, false, false);
820 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
821 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, /*id*/ 1));
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400822
823 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips3380be92020-09-25 12:47:10 -0400824 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400825 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 0);
826 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 1);
Robert Phillipsdefd2232020-09-25 15:25:46 -0400827
828 helper.checkImage(reporter);
829 helper.checkImage(reporter, helper.snap1());
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400830}
831
Robert Phillips375e1f62020-10-23 16:13:57 -0400832DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache3View, reporter, ctxInfo) {
833 test_3(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
834}
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400835
Robert Phillips375e1f62020-10-23 16:13:57 -0400836DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache3Verts, reporter, ctxInfo) {
837 test_3(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
838}
839
840// Case 4: ensure that, if two DDL recorders get in a race, they still end up sharing a single
841// view/vertexData
842static void test_4(GrDirectContext* dContext, skiatest::Reporter* reporter,
843 TestHelper::addAccessFP addAccess,
844 TestHelper::checkFP check) {
845
846 TestHelper helper(dContext);
847
848 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, 1, false, false);
849 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
850 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, /*id*/ 1));
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400851
852 static const bool kFailLookup = true;
Robert Phillips375e1f62020-10-23 16:13:57 -0400853 (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, 2, kFailLookup, false);
854 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), kImageWH,
855 /*hits*/ 0, /*misses*/ 2, /*refs*/ 2, /*id*/ 1));
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400856
857 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips3380be92020-09-25 12:47:10 -0400858 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 0);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400859 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 0);
860 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 2);
Robert Phillipsdefd2232020-09-25 15:25:46 -0400861
862 helper.checkImage(reporter, helper.snap1());
863 helper.checkImage(reporter, helper.snap2());
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400864}
Robert Phillips752f7e12020-09-18 12:28:59 -0400865
Robert Phillips375e1f62020-10-23 16:13:57 -0400866DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache4View, reporter, ctxInfo) {
867 test_4(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
868}
Robert Phillips3380be92020-09-25 12:47:10 -0400869
Robert Phillips375e1f62020-10-23 16:13:57 -0400870DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache4Verts, reporter, ctxInfo) {
871 test_4(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
872}
873
874// Case 4.5: check that, if a live rendering and a DDL recording get into a race, the live
875// rendering takes precedence.
876static void test_4_5(GrDirectContext* dContext, skiatest::Reporter* reporter,
877 TestHelper::addAccessFP addAccess,
878 TestHelper::checkFP check) {
879
880 TestHelper helper(dContext);
881
882 (helper.*addAccess)(helper.liveCanvas(), kImageWH, 1, false, false);
883 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
884 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, /*id*/ 1));
Robert Phillips3380be92020-09-25 12:47:10 -0400885
886 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
887 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
888 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 1);
889 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0);
890
891 static const bool kFailLookup = true;
Robert Phillips375e1f62020-10-23 16:13:57 -0400892 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, 2, kFailLookup, false);
893 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
894 /*hits*/ 0, /*misses*/ 2, /*refs*/ 2, /*id*/ 1));
Robert Phillips3380be92020-09-25 12:47:10 -0400895
896 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
897 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
898 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 1);
899 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 1);
Robert Phillipsdefd2232020-09-25 15:25:46 -0400900
901 helper.checkImage(reporter);
902 helper.checkImage(reporter, helper.snap1());
Robert Phillips3380be92020-09-25 12:47:10 -0400903}
904
Robert Phillips375e1f62020-10-23 16:13:57 -0400905DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache4_5View, reporter, ctxInfo) {
906 test_4_5(ctxInfo.directContext(), reporter,
907 &TestHelper::addViewAccess, &TestHelper::checkView);
908}
909
910DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache4_5Verts, reporter, ctxInfo) {
911 test_4_5(ctxInfo.directContext(), reporter,
912 &TestHelper::addVertAccess, &TestHelper::checkVert);
913}
914
Robert Phillips3380be92020-09-25 12:47:10 -0400915// Case 4.75: check that, if a live rendering fails to generate the content needed to instantiate
916// its lazy proxy, life goes on
Robert Phillips375e1f62020-10-23 16:13:57 -0400917static void test_4_75(GrDirectContext* dContext, skiatest::Reporter* reporter,
918 TestHelper::addAccessFP addAccess,
919 TestHelper::checkFP check) {
Robert Phillips3380be92020-09-25 12:47:10 -0400920
921 TestHelper helper(dContext);
922
923 static const bool kFailFillingIn = true;
Robert Phillips375e1f62020-10-23 16:13:57 -0400924 (helper.*addAccess)(helper.liveCanvas(), kImageWH, kNoID, false, kFailFillingIn);
925 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
926 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
Robert Phillips3380be92020-09-25 12:47:10 -0400927
928 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
929 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
930 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 0);
931 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0);
932
933 dContext->flush();
934 dContext->submit(true);
935
Robert Phillips375e1f62020-10-23 16:13:57 -0400936 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
937 /*hits*/ 0, /*misses*/ 1, /*refs*/ 0, kNoID));
Robert Phillips3380be92020-09-25 12:47:10 -0400938
939 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
940 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
941 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 0);
942 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0);
943}
944
Robert Phillips375e1f62020-10-23 16:13:57 -0400945DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache4_75View, reporter, ctxInfo) {
946 test_4_75(ctxInfo.directContext(), reporter,
947 &TestHelper::addViewAccess, &TestHelper::checkView);
948}
949
950DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache4_75Verts, reporter, ctxInfo) {
951 test_4_75(ctxInfo.directContext(), reporter,
952 &TestHelper::addVertAccess, &TestHelper::checkVert);
953}
954
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400955// Case 5: ensure that expanding the map works (esp. wrt custom data)
Robert Phillips375e1f62020-10-23 16:13:57 -0400956static void test_5(GrDirectContext* dContext, skiatest::Reporter* reporter,
957 TestHelper::addAccessFP addAccess,
958 TestHelper::checkFP check) {
959
960 TestHelper helper(dContext);
Robert Phillips752f7e12020-09-18 12:28:59 -0400961
Robert Phillipsd464feb2020-10-08 11:00:02 -0400962 auto threadSafeCache = helper.threadSafeCache();
Robert Phillips752f7e12020-09-18 12:28:59 -0400963
964 int size = 16;
Robert Phillips375e1f62020-10-23 16:13:57 -0400965 (helper.*addAccess)(helper.ddlCanvas1(), size, /*id*/ size, false, false);
Robert Phillips752f7e12020-09-18 12:28:59 -0400966
Robert Phillipsd464feb2020-10-08 11:00:02 -0400967 size_t initialSize = threadSafeCache->approxBytesUsedForHash();
Robert Phillips752f7e12020-09-18 12:28:59 -0400968
Robert Phillipsd464feb2020-10-08 11:00:02 -0400969 while (initialSize == threadSafeCache->approxBytesUsedForHash()) {
Robert Phillips752f7e12020-09-18 12:28:59 -0400970 size *= 2;
Robert Phillips375e1f62020-10-23 16:13:57 -0400971 (helper.*addAccess)(helper.ddlCanvas1(), size, /*id*/ size, false, false);
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400972 }
973
974 for (int i = 16; i <= size; i *= 2) {
Robert Phillips375e1f62020-10-23 16:13:57 -0400975 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(),
976 /*wh*/ i,
977 /*hits*/ 0,
978 /*misses*/ threadSafeCache->numEntries(),
979 /*refs*/ 1,
980 /*id*/ i));
Robert Phillips752f7e12020-09-18 12:28:59 -0400981 }
982}
983
Robert Phillips375e1f62020-10-23 16:13:57 -0400984DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache5View, reporter, ctxInfo) {
985 test_5(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
986}
987
988DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache5Verts, reporter, ctxInfo) {
989 test_5(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
990}
991
Robert Phillipsdefd2232020-09-25 15:25:46 -0400992// Case 6: Check on dropping refs. In particular, that the cache has its own ref to keep
Robert Phillips375e1f62020-10-23 16:13:57 -0400993// the backing resource alive and locked.
994static void test_6(GrDirectContext* dContext, skiatest::Reporter* reporter,
995 TestHelper::addAccessFP addAccess,
996 TestHelper::checkFP check) {
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400997
Robert Phillips375e1f62020-10-23 16:13:57 -0400998 TestHelper helper(dContext);
999
1000 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false);
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -04001001 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
Robert Phillips375e1f62020-10-23 16:13:57 -04001002 REPORTER_ASSERT(reporter, (helper.*check)(nullptr, kImageWH,
1003 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -04001004
Robert Phillips375e1f62020-10-23 16:13:57 -04001005 (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, kNoID, false, false);
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -04001006 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
Robert Phillips375e1f62020-10-23 16:13:57 -04001007 REPORTER_ASSERT(reporter, (helper.*check)(nullptr, kImageWH,
1008 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, kNoID));
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -04001009
1010 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
1011
1012 ddl1 = nullptr;
Robert Phillips375e1f62020-10-23 16:13:57 -04001013 REPORTER_ASSERT(reporter, (helper.*check)(nullptr, kImageWH,
1014 /*hits*/ 1, /*misses*/ 1, /*refs*/ 1, kNoID));
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -04001015
1016 ddl2 = nullptr;
Robert Phillips375e1f62020-10-23 16:13:57 -04001017 REPORTER_ASSERT(reporter, (helper.*check)(nullptr, kImageWH,
1018 /*hits*/ 1, /*misses*/ 1, /*refs*/ 0, kNoID));
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -04001019
1020 // The cache still has its ref
1021 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
1022
Robert Phillips375e1f62020-10-23 16:13:57 -04001023 REPORTER_ASSERT(reporter, (helper.*check)(nullptr, kImageWH,
1024 /*hits*/ 1, /*misses*/ 1, /*refs*/ 0, kNoID));
1025}
1026
1027DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache6View, reporter, ctxInfo) {
1028 test_6(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
1029}
1030
1031DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache6Verts, reporter, ctxInfo) {
1032 test_6(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -04001033}
Robert Phillips45593682020-09-18 16:16:33 -04001034
Robert Phillipsdefd2232020-09-25 15:25:46 -04001035// Case 7: Check that invoking dropAllRefs and dropUniqueRefs directly works as expected; i.e.,
Robert Phillips375e1f62020-10-23 16:13:57 -04001036// dropAllRefs removes everything while dropUniqueRefs is more measured.
1037static void test_7(GrDirectContext* dContext, skiatest::Reporter* reporter,
1038 TestHelper::addAccessFP addAccess,
1039 TestHelper::checkFP check) {
Robert Phillips45593682020-09-18 16:16:33 -04001040
Robert Phillips375e1f62020-10-23 16:13:57 -04001041 TestHelper helper(dContext);
1042
1043 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false);
Robert Phillips45593682020-09-18 16:16:33 -04001044 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
Robert Phillips375e1f62020-10-23 16:13:57 -04001045 REPORTER_ASSERT(reporter, (helper.*check)(nullptr, kImageWH,
1046 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
Robert Phillips45593682020-09-18 16:16:33 -04001047
Robert Phillips375e1f62020-10-23 16:13:57 -04001048 (helper.*addAccess)(helper.ddlCanvas2(), 2*kImageWH, kNoID, false, false);
Robert Phillips45593682020-09-18 16:16:33 -04001049 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
Robert Phillips375e1f62020-10-23 16:13:57 -04001050 REPORTER_ASSERT(reporter, (helper.*check)(nullptr, 2*kImageWH,
1051 /*hits*/ 0, /*misses*/ 2, /*refs*/ 1, kNoID));
Robert Phillips45593682020-09-18 16:16:33 -04001052
1053 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
1054
Robert Phillipsd464feb2020-10-08 11:00:02 -04001055 helper.threadSafeCache()->dropUniqueRefs(nullptr);
Robert Phillips45593682020-09-18 16:16:33 -04001056 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
1057
1058 ddl1 = nullptr;
1059
Robert Phillipsd464feb2020-10-08 11:00:02 -04001060 helper.threadSafeCache()->dropUniqueRefs(nullptr);
Robert Phillips45593682020-09-18 16:16:33 -04001061 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips375e1f62020-10-23 16:13:57 -04001062 REPORTER_ASSERT(reporter, (helper.*check)(nullptr, 2*kImageWH,
1063 /*hits*/ 0, /*misses*/ 2, /*refs*/ 1, kNoID));
Robert Phillips45593682020-09-18 16:16:33 -04001064
Robert Phillipsd464feb2020-10-08 11:00:02 -04001065 helper.threadSafeCache()->dropAllRefs();
Robert Phillips45593682020-09-18 16:16:33 -04001066 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0);
1067
1068 ddl2 = nullptr;
1069}
Robert Phillips187b04b2020-09-22 12:18:16 -04001070
Robert Phillips375e1f62020-10-23 16:13:57 -04001071DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache7View, reporter, ctxInfo) {
1072 test_7(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
1073}
1074
1075DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache7Verts, reporter, ctxInfo) {
1076 test_7(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
1077}
1078
Robert Phillips187b04b2020-09-22 12:18:16 -04001079// Case 8: This checks that GrContext::abandonContext works as expected wrt the thread
1080// safe cache. This simulates the case where we have one DDL that has finished
1081// recording but one still recording when the abandonContext fires.
Robert Phillips375e1f62020-10-23 16:13:57 -04001082static void test_8(GrDirectContext* dContext, skiatest::Reporter* reporter,
1083 TestHelper::addAccessFP addAccess,
1084 TestHelper::checkFP check) {
Robert Phillips187b04b2020-09-22 12:18:16 -04001085
Robert Phillips375e1f62020-10-23 16:13:57 -04001086 TestHelper helper(dContext);
Robert Phillips187b04b2020-09-22 12:18:16 -04001087
Robert Phillips375e1f62020-10-23 16:13:57 -04001088 (helper.*addAccess)(helper.liveCanvas(), kImageWH, kNoID, false, false);
1089 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
1090 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
1091
1092 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false);
Robert Phillips187b04b2020-09-22 12:18:16 -04001093 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
Robert Phillips375e1f62020-10-23 16:13:57 -04001094 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
1095 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001096
Robert Phillips375e1f62020-10-23 16:13:57 -04001097 (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, kNoID, false, false);
1098 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), kImageWH,
1099 /*hits*/ 2, /*misses*/ 1, /*refs*/ 3, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001100
1101 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips3380be92020-09-25 12:47:10 -04001102 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
Robert Phillips187b04b2020-09-22 12:18:16 -04001103 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 1);
1104 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0);
1105
Robert Phillips375e1f62020-10-23 16:13:57 -04001106 dContext->abandonContext(); // This should exercise dropAllRefs
Robert Phillips187b04b2020-09-22 12:18:16 -04001107
1108 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
1109
1110 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0);
1111
1112 ddl1 = nullptr;
1113 ddl2 = nullptr;
1114}
1115
Robert Phillips375e1f62020-10-23 16:13:57 -04001116DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache8View, reporter, ctxInfo) {
1117 test_8(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
1118}
1119
1120DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache8Verts, reporter, ctxInfo) {
1121 test_8(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
1122}
1123
Robert Phillips187b04b2020-09-22 12:18:16 -04001124// Case 9: This checks that GrContext::releaseResourcesAndAbandonContext works as expected wrt
1125// the thread safe cache. This simulates the case where we have one DDL that has finished
1126// recording but one still recording when the releaseResourcesAndAbandonContext fires.
Robert Phillips375e1f62020-10-23 16:13:57 -04001127static void test_9(GrDirectContext* dContext, skiatest::Reporter* reporter,
1128 TestHelper::addAccessFP addAccess,
1129 TestHelper::checkFP check) {
Robert Phillips187b04b2020-09-22 12:18:16 -04001130
Robert Phillips375e1f62020-10-23 16:13:57 -04001131 TestHelper helper(dContext);
Robert Phillips187b04b2020-09-22 12:18:16 -04001132
Robert Phillips375e1f62020-10-23 16:13:57 -04001133 (helper.*addAccess)(helper.liveCanvas(), kImageWH, kNoID, false, false);
1134 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
1135 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
1136
1137 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false);
Robert Phillips187b04b2020-09-22 12:18:16 -04001138 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
Robert Phillips375e1f62020-10-23 16:13:57 -04001139 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
1140 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001141
Robert Phillips375e1f62020-10-23 16:13:57 -04001142 (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, kNoID, false, false);
1143 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), kImageWH,
1144 /*hits*/ 2, /*misses*/ 1, /*refs*/ 3, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001145
1146 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips3380be92020-09-25 12:47:10 -04001147 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
Robert Phillips187b04b2020-09-22 12:18:16 -04001148 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 1);
1149 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0);
1150
Robert Phillips375e1f62020-10-23 16:13:57 -04001151 dContext->releaseResourcesAndAbandonContext(); // This should hit dropAllRefs
Robert Phillips187b04b2020-09-22 12:18:16 -04001152
1153 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
1154
1155 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0);
1156
1157 ddl1 = nullptr;
1158 ddl2 = nullptr;
1159}
1160
Robert Phillips375e1f62020-10-23 16:13:57 -04001161DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache9View, reporter, ctxInfo) {
1162 test_9(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
1163}
1164
1165DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache9Verts, reporter, ctxInfo) {
1166 test_9(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
1167}
1168
Robert Phillips187b04b2020-09-22 12:18:16 -04001169// Case 10: This checks that the GrContext::purgeUnlockedResources(size_t) variant works as
1170// expected wrt the thread safe cache. It, in particular, tests out the MRU behavior
1171// of the shared cache.
Robert Phillips375e1f62020-10-23 16:13:57 -04001172static void test_10(GrDirectContext* dContext, skiatest::Reporter* reporter,
1173 TestHelper::addAccessFP addAccess,
1174 TestHelper::checkFP check) {
Brian Salomonb8c4add2021-06-28 09:20:44 -04001175
1176 if (GrBackendApi::kOpenGL != dContext->backend()) {
1177 // The lower-level backends have too much going on for the following simple purging
1178 // test to work
1179 return;
1180 }
1181
Robert Phillips187b04b2020-09-22 12:18:16 -04001182 TestHelper helper(dContext);
1183
Robert Phillips375e1f62020-10-23 16:13:57 -04001184 (helper.*addAccess)(helper.liveCanvas(), kImageWH, kNoID, false, false);
1185 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
1186 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001187
Robert Phillips375e1f62020-10-23 16:13:57 -04001188 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false);
Robert Phillips187b04b2020-09-22 12:18:16 -04001189 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
Robert Phillips375e1f62020-10-23 16:13:57 -04001190 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
1191 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001192
Robert Phillips375e1f62020-10-23 16:13:57 -04001193 (helper.*addAccess)(helper.liveCanvas(), 2*kImageWH, kNoID, false, false);
1194 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH,
1195 /*hits*/ 1, /*misses*/ 2, /*refs*/ 1, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001196
Robert Phillips375e1f62020-10-23 16:13:57 -04001197 (helper.*addAccess)(helper.ddlCanvas2(), 2*kImageWH, kNoID, false, false);
Robert Phillips187b04b2020-09-22 12:18:16 -04001198 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
Robert Phillips375e1f62020-10-23 16:13:57 -04001199 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), 2*kImageWH,
1200 /*hits*/ 2, /*misses*/ 2, /*refs*/ 2, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001201
1202 dContext->flush();
1203 dContext->submit(true);
1204
1205 // This should clear out everything but the textures locked in the thread-safe cache
1206 dContext->purgeUnlockedResources(false);
1207
1208 ddl1 = nullptr;
1209 ddl2 = nullptr;
1210
1211 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
Robert Phillips375e1f62020-10-23 16:13:57 -04001212 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
1213 /*hits*/ 2, /*misses*/ 2, /*refs*/ 0, kNoID));
1214 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH,
1215 /*hits*/ 2, /*misses*/ 2, /*refs*/ 0, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001216
1217 // Regardless of which image is MRU, this should force the other out
1218 size_t desiredBytes = helper.gpuSize(2*kImageWH) + helper.gpuSize(kImageWH)/2;
1219
1220 auto cache = dContext->priv().getResourceCache();
1221 size_t currentBytes = cache->getResourceBytes();
1222
1223 SkASSERT(currentBytes >= desiredBytes);
1224 size_t amountToPurge = currentBytes - desiredBytes;
1225
1226 // The 2*kImageWH texture should be MRU.
1227 dContext->purgeUnlockedResources(amountToPurge, true);
1228
1229 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
1230
Robert Phillips375e1f62020-10-23 16:13:57 -04001231 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH,
1232 /*hits*/ 2, /*misses*/ 2, /*refs*/ 0, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001233}
Robert Phillips331699c2020-09-22 15:20:01 -04001234
Brian Salomonb8c4add2021-06-28 09:20:44 -04001235DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache10View, reporter, ctxInfo) {
1236 test_10(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
Robert Phillips375e1f62020-10-23 16:13:57 -04001237}
1238
1239// To enable test_10 with verts would require a bit more work, namely:
1240// have a different # of verts based on size
1241// also pass in a gpuSize function to 'test_10'
1242//DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache10Verts, reporter, ctxInfo) {
1243// test_10(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
1244//}
1245
Robert Phillips331699c2020-09-22 15:20:01 -04001246// Case 11: This checks that scratch-only variant of GrContext::purgeUnlockedResources works as
Robert Phillipsdefd2232020-09-25 15:25:46 -04001247// expected wrt the thread safe cache. In particular, that when 'scratchResourcesOnly'
1248// is true, the call has no effect on the cache.
Robert Phillips375e1f62020-10-23 16:13:57 -04001249static void test_11(GrDirectContext* dContext, skiatest::Reporter* reporter,
1250 TestHelper::addAccessFP addAccess,
1251 TestHelper::checkFP check) {
Robert Phillips331699c2020-09-22 15:20:01 -04001252
1253 TestHelper helper(dContext);
1254
Robert Phillips375e1f62020-10-23 16:13:57 -04001255 (helper.*addAccess)(helper.liveCanvas(), kImageWH, kNoID, false, false);
1256 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
1257 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
Robert Phillips331699c2020-09-22 15:20:01 -04001258
Robert Phillips375e1f62020-10-23 16:13:57 -04001259 (helper.*addAccess)(helper.liveCanvas(), 2*kImageWH, kNoID, false, false);
1260 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH,
1261 /*hits*/ 0, /*misses*/ 2, /*refs*/ 1, kNoID));
Robert Phillips331699c2020-09-22 15:20:01 -04001262
1263 dContext->flush();
1264 dContext->submit(true);
1265
1266 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
Robert Phillips375e1f62020-10-23 16:13:57 -04001267 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
1268 /*hits*/ 0, /*misses*/ 2, /*refs*/ 0, kNoID));
1269 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH,
1270 /*hits*/ 0, /*misses*/ 2, /*refs*/ 0, kNoID));
Robert Phillips331699c2020-09-22 15:20:01 -04001271
1272 // This shouldn't remove anything from the cache
1273 dContext->purgeUnlockedResources(/* scratchResourcesOnly */ true);
1274
1275 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
1276
1277 dContext->purgeUnlockedResources(/* scratchResourcesOnly */ false);
1278
1279 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0);
1280}
1281
Robert Phillips375e1f62020-10-23 16:13:57 -04001282DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache11View, reporter, ctxInfo) {
1283 test_11(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
1284}
1285
1286DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache11Verts, reporter, ctxInfo) {
1287 test_11(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
1288}
1289
Robert Phillipsdefd2232020-09-25 15:25:46 -04001290// Case 12: Test out purges caused by resetting the cache budget to 0. Note that, due to
1291// the how the cache operates (i.e., not directly driven by ref/unrefs) there
1292// needs to be an explicit kick to purge the cache.
Robert Phillips375e1f62020-10-23 16:13:57 -04001293static void test_12(GrDirectContext* dContext, skiatest::Reporter* reporter,
1294 TestHelper::addAccessFP addAccess,
1295 TestHelper::checkFP check) {
Robert Phillips331699c2020-09-22 15:20:01 -04001296
1297 TestHelper helper(dContext);
1298
Robert Phillips375e1f62020-10-23 16:13:57 -04001299 (helper.*addAccess)(helper.liveCanvas(), kImageWH, kNoID, false, false);
1300 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
1301 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
1302 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false);
Robert Phillips331699c2020-09-22 15:20:01 -04001303 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
Robert Phillips375e1f62020-10-23 16:13:57 -04001304 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
1305 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, kNoID));
Robert Phillips331699c2020-09-22 15:20:01 -04001306
Robert Phillips375e1f62020-10-23 16:13:57 -04001307 (helper.*addAccess)(helper.liveCanvas(), 2*kImageWH, kNoID, false, false);
1308 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH,
1309 /*hits*/ 1, /*misses*/ 2, /*refs*/ 1, kNoID));
Robert Phillips331699c2020-09-22 15:20:01 -04001310
1311 dContext->flush();
1312 dContext->submit(true);
1313
1314 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
Robert Phillips375e1f62020-10-23 16:13:57 -04001315 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
1316 /*hits*/ 1, /*misses*/ 2, /*refs*/ 1, kNoID));
1317 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH,
1318 /*hits*/ 1, /*misses*/ 2, /*refs*/ 0, kNoID));
Robert Phillips331699c2020-09-22 15:20:01 -04001319
1320 dContext->setResourceCacheLimit(0);
1321
1322 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
1323
1324 ddl1 = nullptr;
1325
Robert Phillipsdefd2232020-09-25 15:25:46 -04001326 // Explicitly kick off the purge - it won't happen automatically on unref
Robert Phillips331699c2020-09-22 15:20:01 -04001327 dContext->performDeferredCleanup(std::chrono::milliseconds(0));
1328
1329 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0);
1330}
Robert Phillipsc2fe1642020-09-22 17:34:51 -04001331
Robert Phillips375e1f62020-10-23 16:13:57 -04001332DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache12View, reporter, ctxInfo) {
1333 test_12(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
1334}
1335
1336DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache12Verts, reporter, ctxInfo) {
1337 test_12(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
1338}
1339
Robert Phillipsc2fe1642020-09-22 17:34:51 -04001340// Case 13: Test out the 'msNotUsed' parameter to GrContext::performDeferredCleanup.
Robert Phillips375e1f62020-10-23 16:13:57 -04001341static void test_13(GrDirectContext* dContext, skiatest::Reporter* reporter,
1342 TestHelper::addAccessFP addAccess,
1343 TestHelper::checkFP check) {
Robert Phillipsc2fe1642020-09-22 17:34:51 -04001344
1345 TestHelper helper(dContext);
1346
Robert Phillips375e1f62020-10-23 16:13:57 -04001347 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false);
1348 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
1349 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
Robert Phillipsc2fe1642020-09-22 17:34:51 -04001350 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
1351
1352 std::this_thread::sleep_for(std::chrono::milliseconds(5));
1353 auto firstTime = GrStdSteadyClock::now();
1354 std::this_thread::sleep_for(std::chrono::milliseconds(5));
1355
Robert Phillips375e1f62020-10-23 16:13:57 -04001356 (helper.*addAccess)(helper.ddlCanvas2(), 2*kImageWH, kNoID, false, false);
1357
1358 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), 2*kImageWH,
1359 /*hits*/ 0, /*misses*/ 2, /*refs*/ 1, kNoID));
Robert Phillipsc2fe1642020-09-22 17:34:51 -04001360 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
1361
1362 ddl1 = nullptr;
1363 ddl2 = nullptr;
1364
1365 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
1366
1367 auto secondTime = GrStdSteadyClock::now();
1368
1369 auto msecs = std::chrono::duration_cast<std::chrono::milliseconds>(secondTime - firstTime);
1370 dContext->performDeferredCleanup(msecs);
1371
1372 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips375e1f62020-10-23 16:13:57 -04001373 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH,
1374 /*hits*/ 0, /*misses*/ 2, /*refs*/ 0, kNoID));
1375}
1376
1377DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache13View, reporter, ctxInfo) {
1378 test_13(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
1379}
1380
1381DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache13Verts, reporter, ctxInfo) {
1382 test_13(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
Robert Phillipsc2fe1642020-09-22 17:34:51 -04001383}
Robert Phillips3ac83b2f2020-10-26 13:50:57 -04001384
1385// Case 14: Test out mixing & matching view & vertex data w/ recycling of the cache entries to
1386// wring out the anonymous union code. This is mainly for the MSAN bot's consumption.
1387DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache14, reporter, ctxInfo) {
1388 constexpr int kBestPrimeNumber = 73; // palindromic in binary
1389 SkRandom rand(kBestPrimeNumber);
1390
1391 TestHelper helper(ctxInfo.directContext());
1392
1393 for (int i = 0; i < 2; ++i) {
1394 SkCanvas* ddlCanvas = (!i) ? helper.ddlCanvas1() : helper.ddlCanvas2();
1395
1396 for (int j = 0; j < 10; ++j) {
1397 int numResources = 10*i + j + 1;
1398 int wh = numResources;
1399
1400 if (rand.nextBool()) {
1401 helper.addViewAccess(ddlCanvas, wh, kNoID, false, false);
1402 REPORTER_ASSERT(reporter, helper.checkView(ddlCanvas, wh,
1403 /*hits*/ 0, /*misses*/ numResources,
1404 /*refs*/ 1, kNoID));
1405 } else {
1406 helper.addVertAccess(ddlCanvas, wh, kNoID, false, false);
1407 REPORTER_ASSERT(reporter, helper.checkVert(ddlCanvas, wh,
1408 /*hits*/ 0, /*misses*/ numResources,
1409 /*refs*/ 1, kNoID));
1410 }
1411 }
1412
1413 if (!i) {
1414 // Drop all the accumulated resources from the thread-safe cache
1415 helper.snap1();
1416 ctxInfo.directContext()->purgeUnlockedResources(/* scratchResourcesOnly */ false);
1417 }
1418 }
1419}
Robert Phillips83c38a82020-10-28 14:57:53 -04001420
1421// Case 15: Test out posting invalidation messages that involve the thread safe cache
1422static void test_15(GrDirectContext* dContext, skiatest::Reporter* reporter,
1423 TestHelper::addAccessFP addAccess,
1424 TestHelper::checkFP check,
1425 void (*create_key)(GrUniqueKey*, int wh, int id)) {
1426
1427 TestHelper helper(dContext);
1428
1429 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false);
1430 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
1431 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
1432 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
1433
1434 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
1435
1436 GrUniqueKey key;
1437 (*create_key)(&key, kImageWH, kNoID);
1438
1439 GrUniqueKeyInvalidatedMessage msg(key, dContext->priv().contextID(),
1440 /* inThreadSafeCache */ true);
1441
Robert Phillipse7a959d2021-03-11 14:44:42 -05001442 SkMessageBus<GrUniqueKeyInvalidatedMessage, uint32_t>::Post(msg);
Robert Phillips83c38a82020-10-28 14:57:53 -04001443
1444 // This purge call is needed to process the invalidation messages
1445 dContext->purgeUnlockedResources(/* scratchResourcesOnly */ true);
1446
1447 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0);
1448
1449 (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, kNoID, false, false);
1450 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), kImageWH,
1451 /*hits*/ 0, /*misses*/ 2, /*refs*/ 1, kNoID));
1452 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
1453
1454 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
1455
1456 helper.checkImage(reporter, std::move(ddl1));
1457 helper.checkImage(reporter, std::move(ddl2));
1458}
1459
1460DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache15View, reporter, ctxInfo) {
1461 test_15(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView,
1462 create_view_key);
1463}
1464
1465DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache15Verts, reporter, ctxInfo) {
1466 test_15(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert,
1467 create_vert_key);
1468}
Robert Phillips67e58cb2020-11-02 08:57:39 -05001469
1470// Case 16: Test out pre-emption of an existing vertex-data cache entry. This test simulates
1471// the case where there is a race to create vertex data. However, the second one
1472// to finish is better and usurps the first's position in the cache.
1473//
1474// This capability isn't available for views.
1475
1476static bool newer_is_always_better(SkData* /* incumbent */, SkData* /* challenger */) {
1477 return true;
1478};
1479
1480DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache16Verts, reporter, ctxInfo) {
1481 GrUniqueKey key;
1482 create_vert_key(&key, kImageWH, kNoID);
1483
1484 TestHelper helper(ctxInfo.directContext(), newer_is_always_better);
1485
1486 GrThreadSafeVertexTestOp* op1 = nullptr, *op2 = nullptr;
1487
1488 helper.addVertAccess(helper.ddlCanvas1(), kImageWH, kNoID, false, false, &op1);
1489 REPORTER_ASSERT(reporter, helper.checkVert(helper.ddlCanvas1(), kImageWH,
1490 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
1491 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
1492
1493 {
1494 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
1495 auto [vertexData, xtraData] = helper.threadSafeCache()->findVertsWithData(key);
1496 REPORTER_ASSERT(reporter, vertexData.get() == op1->vertexData());
1497 }
1498
1499 helper.addVertAccess(helper.ddlCanvas2(), kImageWH, kNoID, /* failLookup */ true, false, &op2);
1500 REPORTER_ASSERT(reporter, helper.checkVert(helper.ddlCanvas2(), kImageWH,
1501 /*hits*/ 0, /*misses*/ 2, /*refs*/ 1, kNoID));
1502 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
1503
1504 REPORTER_ASSERT(reporter, op1->vertexData() != op2->vertexData());
1505
1506 {
1507 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
1508 auto [vertexData, xtraData] = helper.threadSafeCache()->findVertsWithData(key);
1509 REPORTER_ASSERT(reporter, vertexData.get() == op2->vertexData());
1510 }
1511
1512 helper.checkImage(reporter, std::move(ddl1));
1513 helper.checkImage(reporter, std::move(ddl2));
1514}