blob: 7e459b0cb47a7cc75212832060ec8ba8a1fbab49 [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 Phillips3380be92020-09-25 12:47:10 -040022#include "src/gpu/GrStyle.h"
Brian Salomoneebe7352020-12-09 16:37:04 -050023#include "src/gpu/GrSurfaceDrawContext.h"
Robert Phillipsd464feb2020-10-08 11:00:02 -040024#include "src/gpu/GrThreadSafeCache.h"
Robert Phillips26f3aeb2020-09-16 10:57:32 -040025#include "tests/Test.h"
26#include "tests/TestUtils.h"
Robert Phillips375e1f62020-10-23 16:13:57 -040027#include "tools/gpu/ProxyUtils.h"
Robert Phillips26f3aeb2020-09-16 10:57:32 -040028
Robert Phillipsc2fe1642020-09-22 17:34:51 -040029#include <thread>
30
Robert Phillips26f3aeb2020-09-16 10:57:32 -040031static constexpr int kImageWH = 32;
32static constexpr auto kImageOrigin = kBottomLeft_GrSurfaceOrigin;
Robert Phillips6e17ffe2020-10-06 14:52:11 -040033static constexpr int kNoID = -1;
Robert Phillips26f3aeb2020-09-16 10:57:32 -040034
35static SkImageInfo default_ii(int wh) {
36 return SkImageInfo::Make(wh, wh, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
37}
38
Brian Salomoneebe7352020-12-09 16:37:04 -050039static std::unique_ptr<GrSurfaceDrawContext> new_RTC(GrRecordingContext* rContext, int wh) {
40 return GrSurfaceDrawContext::Make(rContext,
41 GrColorType::kRGBA_8888,
42 nullptr,
43 SkBackingFit::kExact,
44 {wh, wh},
45 1,
46 GrMipMapped::kNo,
47 GrProtected::kNo,
48 kImageOrigin,
49 SkBudgeted::kYes);
Robert Phillips3380be92020-09-25 12:47:10 -040050}
51
Robert Phillips375e1f62020-10-23 16:13:57 -040052static void create_view_key(GrUniqueKey* key, int wh, int id) {
53 static const GrUniqueKey::Domain kViewDomain = GrUniqueKey::GenerateDomain();
54 GrUniqueKey::Builder builder(key, kViewDomain, 1);
Robert Phillips26f3aeb2020-09-16 10:57:32 -040055 builder[0] = wh;
56 builder.finish();
Robert Phillips6e17ffe2020-10-06 14:52:11 -040057
58 if (id != kNoID) {
59 key->setCustomData(SkData::MakeWithCopy(&id, sizeof(id)));
60 }
Robert Phillips375e1f62020-10-23 16:13:57 -040061}
Robert Phillips26f3aeb2020-09-16 10:57:32 -040062
Robert Phillips375e1f62020-10-23 16:13:57 -040063static void create_vert_key(GrUniqueKey* key, int wh, int id) {
64 static const GrUniqueKey::Domain kVertDomain = GrUniqueKey::GenerateDomain();
65 GrUniqueKey::Builder builder(key, kVertDomain, 1);
66 builder[0] = wh;
67 builder.finish();
68
69 if (id != kNoID) {
70 key->setCustomData(SkData::MakeWithCopy(&id, sizeof(id)));
71 }
72}
73
Robert Phillips67e58cb2020-11-02 08:57:39 -050074static bool default_is_newer_better(SkData* incumbent, SkData* challenger) {
75 return false;
76}
77
Robert Phillips375e1f62020-10-23 16:13:57 -040078// When testing views we create a bitmap that covers the entire screen and has an inset blue rect
79// atop a field of white.
80// When testing verts we clear the background to white and simply draw an inset blur rect.
Robert Phillips3380be92020-09-25 12:47:10 -040081static SkBitmap create_bitmap(int wh) {
Robert Phillips26f3aeb2020-09-16 10:57:32 -040082 SkBitmap bitmap;
83
84 bitmap.allocPixels(default_ii(wh));
85
86 SkCanvas tmp(bitmap);
87 tmp.clear(SK_ColorWHITE);
88
89 SkPaint blue;
90 blue.setColor(SK_ColorBLUE);
Robert Phillips3380be92020-09-25 12:47:10 -040091 blue.setAntiAlias(false);
Robert Phillips26f3aeb2020-09-16 10:57:32 -040092
Robert Phillips3380be92020-09-25 12:47:10 -040093 tmp.drawRect({10, 10, wh-10.0f, wh-10.0f}, blue);
Robert Phillips26f3aeb2020-09-16 10:57:32 -040094
Robert Phillipsdefd2232020-09-25 15:25:46 -040095 bitmap.setImmutable();
Robert Phillips26f3aeb2020-09-16 10:57:32 -040096 return bitmap;
97}
98
Robert Phillips67e58cb2020-11-02 08:57:39 -050099class GrThreadSafeVertexTestOp;
100
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400101class TestHelper {
102public:
103 struct Stats {
104 int fCacheHits = 0;
105 int fCacheMisses = 0;
106
107 int fNumSWCreations = 0;
Robert Phillips3380be92020-09-25 12:47:10 -0400108 int fNumLazyCreations = 0;
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400109 int fNumHWCreations = 0;
110 };
111
Robert Phillips67e58cb2020-11-02 08:57:39 -0500112 TestHelper(GrDirectContext* dContext,
113 GrThreadSafeCache::IsNewerBetter isNewerBetter = default_is_newer_better)
114 : fDContext(dContext)
115 , fIsNewerBetter(isNewerBetter) {
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400116
117 fDst = SkSurface::MakeRenderTarget(dContext, SkBudgeted::kNo, default_ii(kImageWH));
118 SkAssertResult(fDst);
119
120 SkSurfaceCharacterization characterization;
121 SkAssertResult(fDst->characterize(&characterization));
122
123 fRecorder1 = std::make_unique<SkDeferredDisplayListRecorder>(characterization);
Robert Phillips375e1f62020-10-23 16:13:57 -0400124 this->ddlCanvas1()->clear(SkColors::kWhite);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400125
126 fRecorder2 = std::make_unique<SkDeferredDisplayListRecorder>(characterization);
Robert Phillips375e1f62020-10-23 16:13:57 -0400127 this->ddlCanvas2()->clear(SkColors::kWhite);
128
129 fDst->getCanvas()->clear(SkColors::kWhite);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400130 }
131
132 ~TestHelper() {
Robert Phillips187b04b2020-09-22 12:18:16 -0400133 fDContext->flush();
134 fDContext->submit(true);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400135 }
136
137 Stats* stats() { return &fStats; }
138
Robert Phillipsd464feb2020-10-08 11:00:02 -0400139 int numCacheEntries() const { return this->threadSafeCache()->numEntries(); }
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400140
141 GrDirectContext* dContext() { return fDContext; }
142
143 SkCanvas* liveCanvas() { return fDst ? fDst->getCanvas() : nullptr; }
144 SkCanvas* ddlCanvas1() { return fRecorder1 ? fRecorder1->getCanvas() : nullptr; }
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400145 sk_sp<SkDeferredDisplayList> snap1() {
146 if (fRecorder1) {
147 sk_sp<SkDeferredDisplayList> tmp = fRecorder1->detach();
148 fRecorder1 = nullptr;
149 return tmp;
150 }
151
152 return nullptr;
153 }
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400154 SkCanvas* ddlCanvas2() { return fRecorder2 ? fRecorder2->getCanvas() : nullptr; }
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400155 sk_sp<SkDeferredDisplayList> snap2() {
156 if (fRecorder2) {
157 sk_sp<SkDeferredDisplayList> tmp = fRecorder2->detach();
158 fRecorder2 = nullptr;
159 return tmp;
160 }
161
162 return nullptr;
163 }
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400164
Robert Phillipsd464feb2020-10-08 11:00:02 -0400165 GrThreadSafeCache* threadSafeCache() { return fDContext->priv().threadSafeCache(); }
166 const GrThreadSafeCache* threadSafeCache() const { return fDContext->priv().threadSafeCache(); }
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400167
Robert Phillips375e1f62020-10-23 16:13:57 -0400168 typedef void (TestHelper::*addAccessFP)(SkCanvas*, int wh, int id,
169 bool failLookUp, bool failFillingIn);
170 typedef bool (TestHelper::*checkFP)(SkCanvas*, int wh,
171 int expectedHits, int expectedMisses,
172 int expectedNumRefs, int expectedID);
173
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400174 // Add a draw on 'canvas' that will introduce a ref on the 'wh' view
Robert Phillips375e1f62020-10-23 16:13:57 -0400175 void addViewAccess(SkCanvas* canvas,
176 int wh,
177 int id = kNoID,
178 bool failLookup = false,
179 bool failFillingIn = false) {
180 auto rContext = canvas->recordingContext();
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400181
Robert Phillipsd464feb2020-10-08 11:00:02 -0400182 auto view = AccessCachedView(rContext, this->threadSafeCache(),
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400183 wh, failLookup, failFillingIn, id, &fStats);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400184 SkASSERT(view);
185
Brian Salomon8f7d9532020-12-23 09:16:59 -0500186 auto sdc = SkCanvasPriv::TopDeviceSurfaceDrawContext(canvas);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400187
Brian Salomon8f7d9532020-12-23 09:16:59 -0500188 sdc->drawTexture(nullptr,
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400189 view,
190 kPremul_SkAlphaType,
191 GrSamplerState::Filter::kNearest,
192 GrSamplerState::MipmapMode::kNone,
193 SkBlendMode::kSrcOver,
Robert Phillipsdefd2232020-09-25 15:25:46 -0400194 {1.0f, 1.0f, 1.0f, 1.0f},
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400195 SkRect::MakeWH(wh, wh),
196 SkRect::MakeWH(wh, wh),
197 GrAA::kNo,
198 GrQuadAAFlags::kNone,
199 SkCanvas::kFast_SrcRectConstraint,
200 SkMatrix::I(),
201 nullptr);
202 }
203
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400204 // Besides checking that the number of refs and cache hits and misses are as expected, this
205 // method also validates that the unique key doesn't appear in any of the other caches.
Robert Phillips375e1f62020-10-23 16:13:57 -0400206 bool checkView(SkCanvas* canvas, int wh,
207 int expectedHits, int expectedMisses, int expectedNumRefs, int expectedID) {
208 if (fStats.fCacheHits != expectedHits || fStats.fCacheMisses != expectedMisses) {
Robert Phillips187b04b2020-09-22 12:18:16 -0400209 SkDebugf("Hits E: %d A: %d --- Misses E: %d A: %d\n",
Robert Phillips375e1f62020-10-23 16:13:57 -0400210 expectedHits, fStats.fCacheHits, expectedMisses, fStats.fCacheMisses);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400211 return false;
212 }
213
214 GrUniqueKey key;
Robert Phillips375e1f62020-10-23 16:13:57 -0400215 create_view_key(&key, wh, kNoID);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400216
Robert Phillipsd464feb2020-10-08 11:00:02 -0400217 auto threadSafeCache = this->threadSafeCache();
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400218
Robert Phillips375e1f62020-10-23 16:13:57 -0400219 auto [view, xtraData] = threadSafeCache->findWithData(key);
Robert Phillips187b04b2020-09-22 12:18:16 -0400220 if (!view.proxy()) {
221 return false;
222 }
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400223
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400224 if (expectedID < 0) {
Robert Phillips375e1f62020-10-23 16:13:57 -0400225 if (xtraData) {
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400226 return false;
227 }
228 } else {
Robert Phillips375e1f62020-10-23 16:13:57 -0400229 if (!xtraData) {
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400230 return false;
231 }
232
Robert Phillips375e1f62020-10-23 16:13:57 -0400233 const int* cachedID = static_cast<const int*>(xtraData->data());
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400234 if (*cachedID != expectedID) {
235 return false;
236 }
237 }
238
Robert Phillips375e1f62020-10-23 16:13:57 -0400239 if (!view.proxy()->refCntGreaterThan(expectedNumRefs+1) || // +1 for 'view's ref
240 view.proxy()->refCntGreaterThan(expectedNumRefs+2)) {
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400241 return false;
242 }
243
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400244 if (canvas) {
245 GrRecordingContext* rContext = canvas->recordingContext();
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400246 GrProxyProvider* recordingProxyProvider = rContext->priv().proxyProvider();
247 sk_sp<GrTextureProxy> result = recordingProxyProvider->findProxyByUniqueKey(key);
248 if (result) {
249 // views in this cache should never appear in the recorder's cache
250 return false;
251 }
252 }
253
254 {
255 GrProxyProvider* directProxyProvider = fDContext->priv().proxyProvider();
256 sk_sp<GrTextureProxy> result = directProxyProvider->findProxyByUniqueKey(key);
257 if (result) {
258 // views in this cache should never appear in the main proxy cache
259 return false;
260 }
261 }
262
263 {
264 auto resourceProvider = fDContext->priv().resourceProvider();
265 sk_sp<GrSurface> surf = resourceProvider->findByUniqueKey<GrSurface>(key);
266 if (surf) {
267 // the textures backing the views in this cache should never be discoverable in the
268 // resource cache
269 return false;
270 }
271 }
272
273 return true;
274 }
275
Robert Phillips67e58cb2020-11-02 08:57:39 -0500276 void addVertAccess(SkCanvas* canvas,
277 int wh,
278 int id,
279 bool failLookup,
280 bool failFillingIn,
281 GrThreadSafeVertexTestOp** createdOp);
282
Robert Phillips375e1f62020-10-23 16:13:57 -0400283 // Add a draw on 'canvas' that will introduce a ref on a 'wh' vertex data
284 void addVertAccess(SkCanvas* canvas,
285 int wh,
286 int id = kNoID,
287 bool failLookup = false,
Robert Phillips67e58cb2020-11-02 08:57:39 -0500288 bool failFillingIn = false) {
289 this->addVertAccess(canvas, wh, id, failLookup, failFillingIn, nullptr);
290 }
Robert Phillips375e1f62020-10-23 16:13:57 -0400291
292 bool checkVert(SkCanvas* canvas, int wh,
293 int expectedHits, int expectedMisses, int expectedNumRefs, int expectedID) {
294 if (fStats.fCacheHits != expectedHits || fStats.fCacheMisses != expectedMisses) {
295 SkDebugf("Hits E: %d A: %d --- Misses E: %d A: %d\n",
296 expectedHits, fStats.fCacheHits, expectedMisses, fStats.fCacheMisses);
297 return false;
298 }
299
300 GrUniqueKey key;
301 create_vert_key(&key, wh, kNoID);
302
303 auto threadSafeCache = this->threadSafeCache();
304
305 auto [vertData, xtraData] = threadSafeCache->findVertsWithData(key);
306 if (!vertData) {
307 return false;
308 }
309
310 if (expectedID < 0) {
311 if (xtraData) {
312 return false;
313 }
314 } else {
315 if (!xtraData) {
316 return false;
317 }
318
319 const int* cachedID = static_cast<const int*>(xtraData->data());
320 if (*cachedID != expectedID) {
321 return false;
322 }
323 }
324
325 if (!vertData->refCntGreaterThan(expectedNumRefs+1) || // +1 for 'vertData's ref
326 vertData->refCntGreaterThan(expectedNumRefs+2)) {
327 return false;
328 }
329
330 {
331 auto resourceProvider = fDContext->priv().resourceProvider();
332 sk_sp<GrGpuBuffer> buffer = resourceProvider->findByUniqueKey<GrGpuBuffer>(key);
333 if (buffer) {
334 // the buffer holding the vertex data in this cache should never be discoverable
335 // in the resource cache
336 return false;
337 }
338 }
339
340 return true;
341 }
342
Robert Phillipsdefd2232020-09-25 15:25:46 -0400343 bool checkImage(skiatest::Reporter* reporter, sk_sp<SkSurface> s) {
344 SkBitmap actual;
345
346 actual.allocPixels(default_ii(kImageWH));
347
348 if (!s->readPixels(actual, 0, 0)) {
349 return false;
350 }
351
352 SkBitmap expected = create_bitmap(kImageWH);
353
354 const float tols[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
355
356 auto error = std::function<ComparePixmapsErrorReporter>(
357 [reporter](int x, int y, const float diffs[4]) {
358 SkASSERT(x >= 0 && y >= 0);
359 ERRORF(reporter, "mismatch at %d, %d (%f, %f, %f %f)",
360 x, y, diffs[0], diffs[1], diffs[2], diffs[3]);
361 });
362
363 return ComparePixels(expected.pixmap(), actual.pixmap(), tols, error);
364 }
365
366 bool checkImage(skiatest::Reporter* reporter) {
367 return this->checkImage(reporter, fDst);
368 }
369
370 bool checkImage(skiatest::Reporter* reporter, sk_sp<SkDeferredDisplayList> ddl) {
371 sk_sp<SkSurface> tmp = SkSurface::MakeRenderTarget(fDContext,
372 SkBudgeted::kNo,
373 default_ii(kImageWH));
374 if (!tmp) {
375 return false;
376 }
377
378 if (!tmp->draw(std::move(ddl))) {
379 return false;
380 }
381
382 return this->checkImage(reporter, std::move(tmp));
383 }
384
Robert Phillips187b04b2020-09-22 12:18:16 -0400385 size_t gpuSize(int wh) const {
386 GrBackendFormat format = fDContext->defaultBackendFormat(kRGBA_8888_SkColorType,
387 GrRenderable::kNo);
388
Greg Daniel0eca74c2020-10-01 13:46:00 -0400389 return GrSurface::ComputeSize(format, {wh, wh}, /*colorSamplesPerPixel=*/1,
390 GrMipMapped::kNo, /*binSize=*/false);
Robert Phillips187b04b2020-09-22 12:18:16 -0400391 }
392
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400393private:
394 static GrSurfaceProxyView AccessCachedView(GrRecordingContext*,
Robert Phillipsd464feb2020-10-08 11:00:02 -0400395 GrThreadSafeCache*,
Robert Phillips187b04b2020-09-22 12:18:16 -0400396 int wh,
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400397 bool failLookup, bool failFillingIn, int id,
Robert Phillips3380be92020-09-25 12:47:10 -0400398 Stats*);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400399 static GrSurfaceProxyView CreateViewOnCpu(GrRecordingContext*, int wh, Stats*);
Robert Phillips3380be92020-09-25 12:47:10 -0400400 static bool FillInViewOnGpu(GrDirectContext*, int wh, Stats*,
401 const GrSurfaceProxyView& lazyView,
Robert Phillipsd464feb2020-10-08 11:00:02 -0400402 sk_sp<GrThreadSafeCache::Trampoline>);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400403
404 Stats fStats;
405 GrDirectContext* fDContext = nullptr;
Robert Phillips67e58cb2020-11-02 08:57:39 -0500406 GrThreadSafeCache::IsNewerBetter fIsNewerBetter;
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400407
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400408 sk_sp<SkSurface> fDst;
409 std::unique_ptr<SkDeferredDisplayListRecorder> fRecorder1;
410 std::unique_ptr<SkDeferredDisplayListRecorder> fRecorder2;
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400411};
412
Robert Phillips375e1f62020-10-23 16:13:57 -0400413class GrThreadSafeVertexTestOp : public GrDrawOp {
414public:
415 DEFINE_OP_CLASS_ID
416
Herb Derbyc76d4092020-10-07 16:46:15 -0400417 static GrOp::Owner Make(GrRecordingContext* rContext, TestHelper::Stats* stats,
Robert Phillips67e58cb2020-11-02 08:57:39 -0500418 int wh, int id, bool failLookup, bool failFillingIn,
419 GrThreadSafeCache::IsNewerBetter isNewerBetter) {
Robert Phillips375e1f62020-10-23 16:13:57 -0400420
Herb Derbyc76d4092020-10-07 16:46:15 -0400421 return GrOp::Make<GrThreadSafeVertexTestOp>(
Robert Phillips67e58cb2020-11-02 08:57:39 -0500422 rContext, rContext, stats, wh, id, failLookup, failFillingIn, isNewerBetter);
Robert Phillips375e1f62020-10-23 16:13:57 -0400423 }
424
Robert Phillips67e58cb2020-11-02 08:57:39 -0500425 const GrThreadSafeCache::VertexData* vertexData() const { return fVertexData.get(); }
426
Robert Phillips375e1f62020-10-23 16:13:57 -0400427private:
Herb Derbyc76d4092020-10-07 16:46:15 -0400428 friend class GrOp; // for ctor
Robert Phillips375e1f62020-10-23 16:13:57 -0400429
430 GrThreadSafeVertexTestOp(GrRecordingContext* rContext, TestHelper::Stats* stats, int wh, int id,
Robert Phillips67e58cb2020-11-02 08:57:39 -0500431 bool failLookup, bool failFillingIn,
432 GrThreadSafeCache::IsNewerBetter isNewerBetter)
Robert Phillips375e1f62020-10-23 16:13:57 -0400433 : INHERITED(ClassID())
434 , fStats(stats)
435 , fWH(wh)
436 , fID(id)
Robert Phillips67e58cb2020-11-02 08:57:39 -0500437 , fFailFillingIn(failFillingIn)
438 , fIsNewerBetter(isNewerBetter) {
Robert Phillips375e1f62020-10-23 16:13:57 -0400439 this->setBounds(SkRect::MakeIWH(fWH, fWH), HasAABloat::kNo, IsHairline::kNo);
440
441 // Normally we wouldn't add a ref to the vertex data at this point. However, it is
442 // needed in this unit test to get the ref counts on the uniquely keyed resources
443 // to be as expected.
444 this->findOrCreateVertices(rContext, failLookup, fFailFillingIn);
445 }
446
447 const char* name() const override { return "GrThreadSafeVertexTestOp"; }
448 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
449 GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*,
450 bool hasMixedSampledCoverage, GrClampType) override {
451 return GrProcessorSet::EmptySetAnalysis();
452 }
453
454 GrProgramInfo* createProgramInfo(const GrCaps* caps,
455 SkArenaAlloc* arena,
Adlai Hollere2296f72020-11-19 13:41:26 -0500456 const GrSurfaceProxyView& writeView,
Robert Phillips375e1f62020-10-23 16:13:57 -0400457 GrAppliedClip&& appliedClip,
458 const GrXferProcessor::DstProxyView& dstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -0500459 GrXferBarrierFlags renderPassXferBarriers,
460 GrLoadOp colorLoadOp) const {
Robert Phillips375e1f62020-10-23 16:13:57 -0400461 using namespace GrDefaultGeoProcFactory;
462
463 Color color({ 0.0f, 0.0f, 1.0f, 1.0f });
464
465 auto gp = MakeForDeviceSpace(arena, color,
466 Coverage::kSolid_Type,
467 LocalCoords::kUnused_Type,
468 SkMatrix::I());
469
470 return sk_gpu_test::CreateProgramInfo(caps, arena, writeView,
471 std::move(appliedClip), dstProxyView,
472 gp, SkBlendMode::kSrcOver,
473 GrPrimitiveType::kTriangleStrip,
Greg Daniel42dbca52020-11-20 10:22:43 -0500474 renderPassXferBarriers, colorLoadOp);
Robert Phillips375e1f62020-10-23 16:13:57 -0400475 }
476
477 GrProgramInfo* createProgramInfo(GrOpFlushState* flushState) const {
478 return this->createProgramInfo(&flushState->caps(),
479 flushState->allocator(),
480 flushState->writeView(),
481 flushState->detachAppliedClip(),
482 flushState->dstProxyView(),
Greg Daniel42dbca52020-11-20 10:22:43 -0500483 flushState->renderPassBarriers(),
484 flushState->colorLoadOp());
Robert Phillips375e1f62020-10-23 16:13:57 -0400485 }
486
487 void findOrCreateVertices(GrRecordingContext* rContext, bool failLookup, bool failFillingIn) {
488
489 if (!fVertexData) {
490 auto threadSafeViewCache = rContext->priv().threadSafeCache();
491
492 if (rContext->asDirectContext()) {
493 // The vertex variant doesn't have a correlate to lazyProxies but increment this
494 // here to make the unit tests happy.
495 ++fStats->fNumLazyCreations;
496 }
497
498 GrUniqueKey key;
499 create_vert_key(&key, fWH, fID);
500
501 // We can "fail the lookup" to simulate a threaded race condition
502 auto [cachedVerts, data] = threadSafeViewCache->findVertsWithData(key);
503 if (cachedVerts && !failLookup) {
504 fVertexData = cachedVerts;
505 ++fStats->fCacheHits;
506 return;
507 }
508
509 ++fStats->fCacheMisses;
510 if (!rContext->asDirectContext()) {
511 ++fStats->fNumSWCreations;
512 }
513
514 constexpr size_t kVertSize = sizeof(SkPoint);
515 SkPoint* verts = static_cast<SkPoint*>(sk_malloc_throw(4 * kVertSize));
516
517 verts[0].set(10.0f, 10.0f);
518 verts[1].set(fWH-10.0f, 10.0f);
519 verts[2].set(10.0f, fWH-10.0f);
520 verts[3].set(fWH-10.0f, fWH-10.0f);
521
522 fVertexData = GrThreadSafeCache::MakeVertexData(verts, 4, kVertSize);
523
Robert Phillips67e58cb2020-11-02 08:57:39 -0500524 auto [tmpV, tmpD] = threadSafeViewCache->addVertsWithData(key, fVertexData,
525 fIsNewerBetter);
Robert Phillips375e1f62020-10-23 16:13:57 -0400526 if (tmpV != fVertexData) {
527 // Someone beat us to creating the vertex data. Use that version.
528 fVertexData = tmpV;
529 }
530 }
531
532 if (auto dContext = rContext->asDirectContext(); dContext && !fVertexData->gpuBuffer()) {
533 auto rp = dContext->priv().resourceProvider();
534
535 if (!failFillingIn) {
536 ++fStats->fNumHWCreations;
537
538 sk_sp<GrGpuBuffer> tmp = rp->createBuffer(fVertexData->size(),
539 GrGpuBufferType::kVertex,
540 kStatic_GrAccessPattern,
541 fVertexData->vertices());
542 fVertexData->setGpuBuffer(std::move(tmp));
543 }
544 }
545 }
546
547 void onPrePrepare(GrRecordingContext* rContext,
Adlai Hollere2296f72020-11-19 13:41:26 -0500548 const GrSurfaceProxyView& writeView,
Robert Phillips375e1f62020-10-23 16:13:57 -0400549 GrAppliedClip* clip,
550 const GrXferProcessor::DstProxyView& dstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -0500551 GrXferBarrierFlags renderPassXferBarriers,
552 GrLoadOp colorLoadOp) override {
Robert Phillips375e1f62020-10-23 16:13:57 -0400553 SkArenaAlloc* arena = rContext->priv().recordTimeAllocator();
554
555 // This is equivalent to a GrOpFlushState::detachAppliedClip
556 GrAppliedClip appliedClip = clip ? std::move(*clip) : GrAppliedClip::Disabled();
557
558 fProgramInfo = this->createProgramInfo(rContext->priv().caps(), arena, writeView,
559 std::move(appliedClip), dstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -0500560 renderPassXferBarriers, colorLoadOp);
Robert Phillips375e1f62020-10-23 16:13:57 -0400561
562 rContext->priv().recordProgramInfo(fProgramInfo);
563
564 // This is now a noop (bc it is always called in the ctor) but is where we would normally
565 // create the vertices.
566 this->findOrCreateVertices(rContext, false, fFailFillingIn);
567 }
568
569 void onPrepare(GrOpFlushState* flushState) override {
570 auto dContext = flushState->gpu()->getContext();
571
572 // This call site is not a noop bc this op could've been created on with DDL context
573 // and, therefore, could be lacking a gpu-side buffer
574 this->findOrCreateVertices(dContext, false, fFailFillingIn);
575 }
576
577 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
578 if (!fVertexData || !fVertexData->gpuBuffer()) {
579 return;
580 }
581
582 if (!fProgramInfo) {
583 fProgramInfo = this->createProgramInfo(flushState);
584 }
585
586 flushState->bindPipeline(*fProgramInfo, SkRect::MakeIWH(fWH, fWH));
587 flushState->bindBuffers(nullptr, nullptr, fVertexData->refGpuBuffer());
588 flushState->draw(4, 0);
589 }
590
Robert Phillips67e58cb2020-11-02 08:57:39 -0500591 TestHelper::Stats* fStats;
592 int fWH;
593 int fID;
594 bool fFailFillingIn;
595 GrThreadSafeCache::IsNewerBetter fIsNewerBetter;
Robert Phillips375e1f62020-10-23 16:13:57 -0400596
597 sk_sp<GrThreadSafeCache::VertexData> fVertexData;
Robert Phillips67e58cb2020-11-02 08:57:39 -0500598 GrProgramInfo* fProgramInfo = nullptr;
Robert Phillips375e1f62020-10-23 16:13:57 -0400599
600 using INHERITED = GrDrawOp;
601};
602
603void TestHelper::addVertAccess(SkCanvas* canvas,
604 int wh, int id,
Robert Phillips67e58cb2020-11-02 08:57:39 -0500605 bool failLookup, bool failFillingIn,
606 GrThreadSafeVertexTestOp** createdOp) {
Robert Phillips375e1f62020-10-23 16:13:57 -0400607 auto rContext = canvas->recordingContext();
Brian Salomon8f7d9532020-12-23 09:16:59 -0500608 auto sdc = SkCanvasPriv::TopDeviceSurfaceDrawContext(canvas);
Robert Phillips375e1f62020-10-23 16:13:57 -0400609
Robert Phillips67e58cb2020-11-02 08:57:39 -0500610 GrOp::Owner op = GrThreadSafeVertexTestOp::Make(rContext, &fStats,
611 wh, id,
612 failLookup, failFillingIn,
613 fIsNewerBetter);
614 if (createdOp) {
615 *createdOp = (GrThreadSafeVertexTestOp*) op.get();
616 }
617
Brian Salomon8f7d9532020-12-23 09:16:59 -0500618 sdc->addDrawOp(std::move(op));
Robert Phillips375e1f62020-10-23 16:13:57 -0400619}
620
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400621GrSurfaceProxyView TestHelper::CreateViewOnCpu(GrRecordingContext* rContext,
622 int wh,
623 Stats* stats) {
624 GrProxyProvider* proxyProvider = rContext->priv().proxyProvider();
625
Robert Phillips3380be92020-09-25 12:47:10 -0400626 sk_sp<GrTextureProxy> proxy = proxyProvider->createProxyFromBitmap(create_bitmap(wh),
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400627 GrMipmapped::kNo,
628 SkBackingFit::kExact,
629 SkBudgeted::kYes);
630 if (!proxy) {
631 return {};
632 }
633
634 GrSwizzle swizzle = rContext->priv().caps()->getReadSwizzle(proxy->backendFormat(),
635 GrColorType::kRGBA_8888);
636 ++stats->fNumSWCreations;
637 return {std::move(proxy), kImageOrigin, swizzle};
638}
639
Robert Phillipsd464feb2020-10-08 11:00:02 -0400640bool TestHelper::FillInViewOnGpu(GrDirectContext* dContext, int wh, Stats* stats,
641 const GrSurfaceProxyView& lazyView,
642 sk_sp<GrThreadSafeCache::Trampoline> trampoline) {
Robert Phillips3380be92020-09-25 12:47:10 -0400643
Brian Salomoneebe7352020-12-09 16:37:04 -0500644 std::unique_ptr<GrSurfaceDrawContext> rtc = new_RTC(dContext, wh);
Robert Phillips3380be92020-09-25 12:47:10 -0400645
646 GrPaint paint;
647 paint.setColor4f({0.0f, 0.0f, 1.0f, 1.0f});
648
Brian Salomon590f5672020-12-16 11:44:47 -0500649 rtc->clear(SkPMColor4f{1.0f, 1.0f, 1.0f, 1.0f});
Robert Phillips3380be92020-09-25 12:47:10 -0400650 rtc->drawRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(),
651 { 10, 10, wh-10.0f, wh-10.0f }, &GrStyle::SimpleFill());
652
653 ++stats->fNumHWCreations;
654 auto view = rtc->readSurfaceView();
655
656 SkASSERT(view.swizzle() == lazyView.swizzle());
657 SkASSERT(view.origin() == lazyView.origin());
658 trampoline->fProxy = view.asTextureProxyRef();
659
660 return true;
661}
662
Robert Phillipsd464feb2020-10-08 11:00:02 -0400663GrSurfaceProxyView TestHelper::AccessCachedView(GrRecordingContext* rContext,
664 GrThreadSafeCache* threadSafeCache,
665 int wh,
666 bool failLookup, bool failFillingIn, int id,
667 Stats* stats) {
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400668 GrUniqueKey key;
Robert Phillips375e1f62020-10-23 16:13:57 -0400669 create_view_key(&key, wh, id);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400670
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400671 if (GrDirectContext* dContext = rContext->asDirectContext()) {
Robert Phillips3380be92020-09-25 12:47:10 -0400672 // The gpu thread gets priority over the recording threads. If the gpu thread is first,
673 // it crams a lazy proxy into the cache and then fills it in later.
Robert Phillipsd464feb2020-10-08 11:00:02 -0400674 auto [lazyView, trampoline] = GrThreadSafeCache::CreateLazyView(
Robert Phillipsfde67e42020-10-07 15:33:43 -0400675 dContext, GrColorType::kRGBA_8888, {wh, wh}, kImageOrigin, SkBackingFit::kExact);
Robert Phillipsb1807122020-10-06 16:44:18 -0400676 ++stats->fNumLazyCreations;
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400677
Robert Phillipsd464feb2020-10-08 11:00:02 -0400678 auto [view, data] = threadSafeCache->findOrAddWithData(key, lazyView);
Robert Phillips3380be92020-09-25 12:47:10 -0400679 if (view != lazyView) {
680 ++stats->fCacheHits;
681 return view;
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400682 } else if (id != kNoID) {
683 // Make sure, in this case, that the customData stuck
684 SkASSERT(data);
685 SkDEBUGCODE(const int* cachedID = static_cast<const int*>(data->data());)
686 SkASSERT(*cachedID == id);
Robert Phillips3380be92020-09-25 12:47:10 -0400687 }
688
689 ++stats->fCacheMisses;
690
691 if (failFillingIn) {
692 // Simulate something going horribly wrong at flush-time so no GrTexture is
693 // available to fulfill the lazy proxy.
694 return view;
695 }
696
697 if (!FillInViewOnGpu(dContext, wh, stats, lazyView, std::move(trampoline))) {
698 // In this case something has gone disastrously wrong so set up to drop the draw
699 // that needed this resource and reduce future pollution of the cache.
Robert Phillipsd464feb2020-10-08 11:00:02 -0400700 threadSafeCache->remove(key);
Robert Phillips3380be92020-09-25 12:47:10 -0400701 return {};
702 }
703
704 return view;
705 } else {
706 GrSurfaceProxyView view;
707
708 // We can "fail the lookup" to simulate a threaded race condition
Robert Phillipsd464feb2020-10-08 11:00:02 -0400709 if (view = threadSafeCache->find(key); !failLookup && view) {
Robert Phillips3380be92020-09-25 12:47:10 -0400710 ++stats->fCacheHits;
711 return view;
712 }
713
714 ++stats->fCacheMisses;
715
716 view = CreateViewOnCpu(rContext, wh, stats);
717 SkASSERT(view);
718
Robert Phillipsd464feb2020-10-08 11:00:02 -0400719 auto [newView, data] = threadSafeCache->addWithData(key, view);
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400720 if (view == newView && id != kNoID) {
721 // Make sure, in this case, that the customData stuck
722 SkASSERT(data);
723 SkDEBUGCODE(const int* cachedID = static_cast<const int*>(data->data());)
724 SkASSERT(*cachedID == id);
725 }
726 return newView;
Robert Phillips3380be92020-09-25 12:47:10 -0400727 }
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400728}
729
Robert Phillips375e1f62020-10-23 16:13:57 -0400730// Case 1: ensure two DDL recorders share the view/vertexData
731static void test_1(GrDirectContext* dContext, skiatest::Reporter* reporter,
732 TestHelper::addAccessFP addAccess,
733 TestHelper::checkFP check) {
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400734
Robert Phillips375e1f62020-10-23 16:13:57 -0400735 TestHelper helper(dContext);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400736
Robert Phillips375e1f62020-10-23 16:13:57 -0400737 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, 1, false, false);
738 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
739 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, /*id*/ 1));
740
741 (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, 2, false, false);
742 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), kImageWH,
743 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, /*id*/ 1));
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400744
745 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips3380be92020-09-25 12:47:10 -0400746 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 0);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400747 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 0);
748 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 1);
Robert Phillipsdefd2232020-09-25 15:25:46 -0400749
750 helper.checkImage(reporter, helper.snap1());
751 helper.checkImage(reporter, helper.snap2());
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400752}
753
Robert Phillips375e1f62020-10-23 16:13:57 -0400754DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache1View, reporter, ctxInfo) {
755 test_1(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
756}
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400757
Robert Phillips375e1f62020-10-23 16:13:57 -0400758DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache1Verts, reporter, ctxInfo) {
759 test_1(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
760}
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400761
Robert Phillips375e1f62020-10-23 16:13:57 -0400762// Case 2: ensure that, if the direct context version wins, its result is reused by the
763// DDL recorders
764static void test_2(GrDirectContext* dContext, skiatest::Reporter* reporter,
765 TestHelper::addAccessFP addAccess,
766 TestHelper::checkFP check) {
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400767
Robert Phillips375e1f62020-10-23 16:13:57 -0400768 TestHelper helper(dContext);
769
770 (helper.*addAccess)(helper.liveCanvas(), kImageWH, 1, false, false);
771 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
772 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, /*id*/ 1));
773
774 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, 2, false, false);
775 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
776 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, /*id*/ 1));
777
778 (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, 3, false, false);
779 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), kImageWH,
780 /*hits*/ 2, /*misses*/ 1, /*refs*/ 3, /*id*/ 1));
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400781
782 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips3380be92020-09-25 12:47:10 -0400783 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400784 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 1);
785 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0);
Robert Phillipsdefd2232020-09-25 15:25:46 -0400786
787 helper.checkImage(reporter);
788 helper.checkImage(reporter, helper.snap1());
789 helper.checkImage(reporter, helper.snap2());
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400790}
791
Robert Phillips375e1f62020-10-23 16:13:57 -0400792DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache2View, reporter, ctxInfo) {
793 test_2(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
794}
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400795
Robert Phillips375e1f62020-10-23 16:13:57 -0400796DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache2Verts, reporter, ctxInfo) {
797 test_2(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
798}
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400799
Robert Phillips375e1f62020-10-23 16:13:57 -0400800// Case 3: ensure that, if the cpu-version wins, its result is reused by the direct context
801static void test_3(GrDirectContext* dContext, skiatest::Reporter* reporter,
802 TestHelper::addAccessFP addAccess,
803 TestHelper::checkFP check) {
804
805 TestHelper helper(dContext);
806
807 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, 1, false, false);
808 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
809 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, /*id*/ 1));
810
811 (helper.*addAccess)(helper.liveCanvas(), kImageWH, 2, false, false);
812 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
813 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, /*id*/ 1));
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400814
815 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips3380be92020-09-25 12:47:10 -0400816 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400817 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 0);
818 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 1);
Robert Phillipsdefd2232020-09-25 15:25:46 -0400819
820 helper.checkImage(reporter);
821 helper.checkImage(reporter, helper.snap1());
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400822}
823
Robert Phillips375e1f62020-10-23 16:13:57 -0400824DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache3View, reporter, ctxInfo) {
825 test_3(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
826}
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400827
Robert Phillips375e1f62020-10-23 16:13:57 -0400828DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache3Verts, reporter, ctxInfo) {
829 test_3(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
830}
831
832// Case 4: ensure that, if two DDL recorders get in a race, they still end up sharing a single
833// view/vertexData
834static void test_4(GrDirectContext* dContext, skiatest::Reporter* reporter,
835 TestHelper::addAccessFP addAccess,
836 TestHelper::checkFP check) {
837
838 TestHelper helper(dContext);
839
840 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, 1, false, false);
841 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
842 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, /*id*/ 1));
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400843
844 static const bool kFailLookup = true;
Robert Phillips375e1f62020-10-23 16:13:57 -0400845 (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, 2, kFailLookup, false);
846 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), kImageWH,
847 /*hits*/ 0, /*misses*/ 2, /*refs*/ 2, /*id*/ 1));
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400848
849 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips3380be92020-09-25 12:47:10 -0400850 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 0);
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400851 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 0);
852 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 2);
Robert Phillipsdefd2232020-09-25 15:25:46 -0400853
854 helper.checkImage(reporter, helper.snap1());
855 helper.checkImage(reporter, helper.snap2());
Robert Phillips26f3aeb2020-09-16 10:57:32 -0400856}
Robert Phillips752f7e12020-09-18 12:28:59 -0400857
Robert Phillips375e1f62020-10-23 16:13:57 -0400858DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache4View, reporter, ctxInfo) {
859 test_4(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
860}
Robert Phillips3380be92020-09-25 12:47:10 -0400861
Robert Phillips375e1f62020-10-23 16:13:57 -0400862DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache4Verts, reporter, ctxInfo) {
863 test_4(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
864}
865
866// Case 4.5: check that, if a live rendering and a DDL recording get into a race, the live
867// rendering takes precedence.
868static void test_4_5(GrDirectContext* dContext, skiatest::Reporter* reporter,
869 TestHelper::addAccessFP addAccess,
870 TestHelper::checkFP check) {
871
872 TestHelper helper(dContext);
873
874 (helper.*addAccess)(helper.liveCanvas(), kImageWH, 1, false, false);
875 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
876 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, /*id*/ 1));
Robert Phillips3380be92020-09-25 12:47:10 -0400877
878 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
879 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
880 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 1);
881 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0);
882
883 static const bool kFailLookup = true;
Robert Phillips375e1f62020-10-23 16:13:57 -0400884 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, 2, kFailLookup, false);
885 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
886 /*hits*/ 0, /*misses*/ 2, /*refs*/ 2, /*id*/ 1));
Robert Phillips3380be92020-09-25 12:47:10 -0400887
888 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
889 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
890 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 1);
891 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 1);
Robert Phillipsdefd2232020-09-25 15:25:46 -0400892
893 helper.checkImage(reporter);
894 helper.checkImage(reporter, helper.snap1());
Robert Phillips3380be92020-09-25 12:47:10 -0400895}
896
Robert Phillips375e1f62020-10-23 16:13:57 -0400897DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache4_5View, reporter, ctxInfo) {
898 test_4_5(ctxInfo.directContext(), reporter,
899 &TestHelper::addViewAccess, &TestHelper::checkView);
900}
901
902DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache4_5Verts, reporter, ctxInfo) {
903 test_4_5(ctxInfo.directContext(), reporter,
904 &TestHelper::addVertAccess, &TestHelper::checkVert);
905}
906
Robert Phillips3380be92020-09-25 12:47:10 -0400907// Case 4.75: check that, if a live rendering fails to generate the content needed to instantiate
908// its lazy proxy, life goes on
Robert Phillips375e1f62020-10-23 16:13:57 -0400909static void test_4_75(GrDirectContext* dContext, skiatest::Reporter* reporter,
910 TestHelper::addAccessFP addAccess,
911 TestHelper::checkFP check) {
Robert Phillips3380be92020-09-25 12:47:10 -0400912
913 TestHelper helper(dContext);
914
915 static const bool kFailFillingIn = true;
Robert Phillips375e1f62020-10-23 16:13:57 -0400916 (helper.*addAccess)(helper.liveCanvas(), kImageWH, kNoID, false, kFailFillingIn);
917 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
918 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
Robert Phillips3380be92020-09-25 12:47:10 -0400919
920 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
921 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
922 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 0);
923 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0);
924
925 dContext->flush();
926 dContext->submit(true);
927
Robert Phillips375e1f62020-10-23 16:13:57 -0400928 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
929 /*hits*/ 0, /*misses*/ 1, /*refs*/ 0, kNoID));
Robert Phillips3380be92020-09-25 12:47:10 -0400930
931 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
932 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
933 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 0);
934 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0);
935}
936
Robert Phillips375e1f62020-10-23 16:13:57 -0400937DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache4_75View, reporter, ctxInfo) {
938 test_4_75(ctxInfo.directContext(), reporter,
939 &TestHelper::addViewAccess, &TestHelper::checkView);
940}
941
942DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache4_75Verts, reporter, ctxInfo) {
943 test_4_75(ctxInfo.directContext(), reporter,
944 &TestHelper::addVertAccess, &TestHelper::checkVert);
945}
946
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400947// Case 5: ensure that expanding the map works (esp. wrt custom data)
Robert Phillips375e1f62020-10-23 16:13:57 -0400948static void test_5(GrDirectContext* dContext, skiatest::Reporter* reporter,
949 TestHelper::addAccessFP addAccess,
950 TestHelper::checkFP check) {
951
952 TestHelper helper(dContext);
Robert Phillips752f7e12020-09-18 12:28:59 -0400953
Robert Phillipsd464feb2020-10-08 11:00:02 -0400954 auto threadSafeCache = helper.threadSafeCache();
Robert Phillips752f7e12020-09-18 12:28:59 -0400955
956 int size = 16;
Robert Phillips375e1f62020-10-23 16:13:57 -0400957 (helper.*addAccess)(helper.ddlCanvas1(), size, /*id*/ size, false, false);
Robert Phillips752f7e12020-09-18 12:28:59 -0400958
Robert Phillipsd464feb2020-10-08 11:00:02 -0400959 size_t initialSize = threadSafeCache->approxBytesUsedForHash();
Robert Phillips752f7e12020-09-18 12:28:59 -0400960
Robert Phillipsd464feb2020-10-08 11:00:02 -0400961 while (initialSize == threadSafeCache->approxBytesUsedForHash()) {
Robert Phillips752f7e12020-09-18 12:28:59 -0400962 size *= 2;
Robert Phillips375e1f62020-10-23 16:13:57 -0400963 (helper.*addAccess)(helper.ddlCanvas1(), size, /*id*/ size, false, false);
Robert Phillips6e17ffe2020-10-06 14:52:11 -0400964 }
965
966 for (int i = 16; i <= size; i *= 2) {
Robert Phillips375e1f62020-10-23 16:13:57 -0400967 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(),
968 /*wh*/ i,
969 /*hits*/ 0,
970 /*misses*/ threadSafeCache->numEntries(),
971 /*refs*/ 1,
972 /*id*/ i));
Robert Phillips752f7e12020-09-18 12:28:59 -0400973 }
974}
975
Robert Phillips375e1f62020-10-23 16:13:57 -0400976DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache5View, reporter, ctxInfo) {
977 test_5(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
978}
979
980DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache5Verts, reporter, ctxInfo) {
981 test_5(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
982}
983
Robert Phillipsdefd2232020-09-25 15:25:46 -0400984// Case 6: Check on dropping refs. In particular, that the cache has its own ref to keep
Robert Phillips375e1f62020-10-23 16:13:57 -0400985// the backing resource alive and locked.
986static void test_6(GrDirectContext* dContext, skiatest::Reporter* reporter,
987 TestHelper::addAccessFP addAccess,
988 TestHelper::checkFP check) {
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400989
Robert Phillips375e1f62020-10-23 16:13:57 -0400990 TestHelper helper(dContext);
991
992 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false);
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400993 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
Robert Phillips375e1f62020-10-23 16:13:57 -0400994 REPORTER_ASSERT(reporter, (helper.*check)(nullptr, kImageWH,
995 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400996
Robert Phillips375e1f62020-10-23 16:13:57 -0400997 (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, kNoID, false, false);
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -0400998 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
Robert Phillips375e1f62020-10-23 16:13:57 -0400999 REPORTER_ASSERT(reporter, (helper.*check)(nullptr, kImageWH,
1000 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, kNoID));
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -04001001
1002 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
1003
1004 ddl1 = nullptr;
Robert Phillips375e1f62020-10-23 16:13:57 -04001005 REPORTER_ASSERT(reporter, (helper.*check)(nullptr, kImageWH,
1006 /*hits*/ 1, /*misses*/ 1, /*refs*/ 1, kNoID));
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -04001007
1008 ddl2 = nullptr;
Robert Phillips375e1f62020-10-23 16:13:57 -04001009 REPORTER_ASSERT(reporter, (helper.*check)(nullptr, kImageWH,
1010 /*hits*/ 1, /*misses*/ 1, /*refs*/ 0, kNoID));
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -04001011
1012 // The cache still has its ref
1013 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
1014
Robert Phillips375e1f62020-10-23 16:13:57 -04001015 REPORTER_ASSERT(reporter, (helper.*check)(nullptr, kImageWH,
1016 /*hits*/ 1, /*misses*/ 1, /*refs*/ 0, kNoID));
1017}
1018
1019DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache6View, reporter, ctxInfo) {
1020 test_6(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
1021}
1022
1023DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache6Verts, reporter, ctxInfo) {
1024 test_6(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
Robert Phillipsf3e2b3c2020-09-18 14:07:43 -04001025}
Robert Phillips45593682020-09-18 16:16:33 -04001026
Robert Phillipsdefd2232020-09-25 15:25:46 -04001027// Case 7: Check that invoking dropAllRefs and dropUniqueRefs directly works as expected; i.e.,
Robert Phillips375e1f62020-10-23 16:13:57 -04001028// dropAllRefs removes everything while dropUniqueRefs is more measured.
1029static void test_7(GrDirectContext* dContext, skiatest::Reporter* reporter,
1030 TestHelper::addAccessFP addAccess,
1031 TestHelper::checkFP check) {
Robert Phillips45593682020-09-18 16:16:33 -04001032
Robert Phillips375e1f62020-10-23 16:13:57 -04001033 TestHelper helper(dContext);
1034
1035 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false);
Robert Phillips45593682020-09-18 16:16:33 -04001036 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
Robert Phillips375e1f62020-10-23 16:13:57 -04001037 REPORTER_ASSERT(reporter, (helper.*check)(nullptr, kImageWH,
1038 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
Robert Phillips45593682020-09-18 16:16:33 -04001039
Robert Phillips375e1f62020-10-23 16:13:57 -04001040 (helper.*addAccess)(helper.ddlCanvas2(), 2*kImageWH, kNoID, false, false);
Robert Phillips45593682020-09-18 16:16:33 -04001041 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
Robert Phillips375e1f62020-10-23 16:13:57 -04001042 REPORTER_ASSERT(reporter, (helper.*check)(nullptr, 2*kImageWH,
1043 /*hits*/ 0, /*misses*/ 2, /*refs*/ 1, kNoID));
Robert Phillips45593682020-09-18 16:16:33 -04001044
1045 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
1046
Robert Phillipsd464feb2020-10-08 11:00:02 -04001047 helper.threadSafeCache()->dropUniqueRefs(nullptr);
Robert Phillips45593682020-09-18 16:16:33 -04001048 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
1049
1050 ddl1 = nullptr;
1051
Robert Phillipsd464feb2020-10-08 11:00:02 -04001052 helper.threadSafeCache()->dropUniqueRefs(nullptr);
Robert Phillips45593682020-09-18 16:16:33 -04001053 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips375e1f62020-10-23 16:13:57 -04001054 REPORTER_ASSERT(reporter, (helper.*check)(nullptr, 2*kImageWH,
1055 /*hits*/ 0, /*misses*/ 2, /*refs*/ 1, kNoID));
Robert Phillips45593682020-09-18 16:16:33 -04001056
Robert Phillipsd464feb2020-10-08 11:00:02 -04001057 helper.threadSafeCache()->dropAllRefs();
Robert Phillips45593682020-09-18 16:16:33 -04001058 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0);
1059
1060 ddl2 = nullptr;
1061}
Robert Phillips187b04b2020-09-22 12:18:16 -04001062
Robert Phillips375e1f62020-10-23 16:13:57 -04001063DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache7View, reporter, ctxInfo) {
1064 test_7(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
1065}
1066
1067DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache7Verts, reporter, ctxInfo) {
1068 test_7(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
1069}
1070
Robert Phillips187b04b2020-09-22 12:18:16 -04001071// Case 8: This checks that GrContext::abandonContext works as expected wrt the thread
1072// safe cache. This simulates the case where we have one DDL that has finished
1073// recording but one still recording when the abandonContext fires.
Robert Phillips375e1f62020-10-23 16:13:57 -04001074static void test_8(GrDirectContext* dContext, skiatest::Reporter* reporter,
1075 TestHelper::addAccessFP addAccess,
1076 TestHelper::checkFP check) {
Robert Phillips187b04b2020-09-22 12:18:16 -04001077
Robert Phillips375e1f62020-10-23 16:13:57 -04001078 TestHelper helper(dContext);
Robert Phillips187b04b2020-09-22 12:18:16 -04001079
Robert Phillips375e1f62020-10-23 16:13:57 -04001080 (helper.*addAccess)(helper.liveCanvas(), kImageWH, kNoID, false, false);
1081 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
1082 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
1083
1084 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false);
Robert Phillips187b04b2020-09-22 12:18:16 -04001085 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
Robert Phillips375e1f62020-10-23 16:13:57 -04001086 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
1087 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001088
Robert Phillips375e1f62020-10-23 16:13:57 -04001089 (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, kNoID, false, false);
1090 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), kImageWH,
1091 /*hits*/ 2, /*misses*/ 1, /*refs*/ 3, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001092
1093 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips3380be92020-09-25 12:47:10 -04001094 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
Robert Phillips187b04b2020-09-22 12:18:16 -04001095 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 1);
1096 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0);
1097
Robert Phillips375e1f62020-10-23 16:13:57 -04001098 dContext->abandonContext(); // This should exercise dropAllRefs
Robert Phillips187b04b2020-09-22 12:18:16 -04001099
1100 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
1101
1102 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0);
1103
1104 ddl1 = nullptr;
1105 ddl2 = nullptr;
1106}
1107
Robert Phillips375e1f62020-10-23 16:13:57 -04001108DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache8View, reporter, ctxInfo) {
1109 test_8(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
1110}
1111
1112DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache8Verts, reporter, ctxInfo) {
1113 test_8(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
1114}
1115
Robert Phillips187b04b2020-09-22 12:18:16 -04001116// Case 9: This checks that GrContext::releaseResourcesAndAbandonContext works as expected wrt
1117// the thread safe cache. This simulates the case where we have one DDL that has finished
1118// recording but one still recording when the releaseResourcesAndAbandonContext fires.
Robert Phillips375e1f62020-10-23 16:13:57 -04001119static void test_9(GrDirectContext* dContext, skiatest::Reporter* reporter,
1120 TestHelper::addAccessFP addAccess,
1121 TestHelper::checkFP check) {
Robert Phillips187b04b2020-09-22 12:18:16 -04001122
Robert Phillips375e1f62020-10-23 16:13:57 -04001123 TestHelper helper(dContext);
Robert Phillips187b04b2020-09-22 12:18:16 -04001124
Robert Phillips375e1f62020-10-23 16:13:57 -04001125 (helper.*addAccess)(helper.liveCanvas(), kImageWH, kNoID, false, false);
1126 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
1127 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
1128
1129 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false);
Robert Phillips187b04b2020-09-22 12:18:16 -04001130 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
Robert Phillips375e1f62020-10-23 16:13:57 -04001131 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
1132 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001133
Robert Phillips375e1f62020-10-23 16:13:57 -04001134 (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, kNoID, false, false);
1135 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), kImageWH,
1136 /*hits*/ 2, /*misses*/ 1, /*refs*/ 3, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001137
1138 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips3380be92020-09-25 12:47:10 -04001139 REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1);
Robert Phillips187b04b2020-09-22 12:18:16 -04001140 REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 1);
1141 REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0);
1142
Robert Phillips375e1f62020-10-23 16:13:57 -04001143 dContext->releaseResourcesAndAbandonContext(); // This should hit dropAllRefs
Robert Phillips187b04b2020-09-22 12:18:16 -04001144
1145 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
1146
1147 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0);
1148
1149 ddl1 = nullptr;
1150 ddl2 = nullptr;
1151}
1152
Robert Phillips375e1f62020-10-23 16:13:57 -04001153DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache9View, reporter, ctxInfo) {
1154 test_9(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
1155}
1156
1157DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache9Verts, reporter, ctxInfo) {
1158 test_9(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
1159}
1160
Robert Phillips187b04b2020-09-22 12:18:16 -04001161// Case 10: This checks that the GrContext::purgeUnlockedResources(size_t) variant works as
1162// expected wrt the thread safe cache. It, in particular, tests out the MRU behavior
1163// of the shared cache.
Robert Phillips375e1f62020-10-23 16:13:57 -04001164static void test_10(GrDirectContext* dContext, skiatest::Reporter* reporter,
1165 TestHelper::addAccessFP addAccess,
1166 TestHelper::checkFP check) {
Robert Phillips187b04b2020-09-22 12:18:16 -04001167
1168 if (GrBackendApi::kOpenGL != dContext->backend()) {
1169 // The lower-level backends have too much going on for the following simple purging
1170 // test to work
1171 return;
1172 }
1173
1174 TestHelper helper(dContext);
1175
Robert Phillips375e1f62020-10-23 16:13:57 -04001176 (helper.*addAccess)(helper.liveCanvas(), kImageWH, kNoID, false, false);
1177 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
1178 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001179
Robert Phillips375e1f62020-10-23 16:13:57 -04001180 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false);
Robert Phillips187b04b2020-09-22 12:18:16 -04001181 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
Robert Phillips375e1f62020-10-23 16:13:57 -04001182 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
1183 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001184
Robert Phillips375e1f62020-10-23 16:13:57 -04001185 (helper.*addAccess)(helper.liveCanvas(), 2*kImageWH, kNoID, false, false);
1186 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH,
1187 /*hits*/ 1, /*misses*/ 2, /*refs*/ 1, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001188
Robert Phillips375e1f62020-10-23 16:13:57 -04001189 (helper.*addAccess)(helper.ddlCanvas2(), 2*kImageWH, kNoID, false, false);
Robert Phillips187b04b2020-09-22 12:18:16 -04001190 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
Robert Phillips375e1f62020-10-23 16:13:57 -04001191 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), 2*kImageWH,
1192 /*hits*/ 2, /*misses*/ 2, /*refs*/ 2, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001193
1194 dContext->flush();
1195 dContext->submit(true);
1196
1197 // This should clear out everything but the textures locked in the thread-safe cache
1198 dContext->purgeUnlockedResources(false);
1199
1200 ddl1 = nullptr;
1201 ddl2 = nullptr;
1202
1203 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
Robert Phillips375e1f62020-10-23 16:13:57 -04001204 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
1205 /*hits*/ 2, /*misses*/ 2, /*refs*/ 0, kNoID));
1206 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH,
1207 /*hits*/ 2, /*misses*/ 2, /*refs*/ 0, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001208
1209 // Regardless of which image is MRU, this should force the other out
1210 size_t desiredBytes = helper.gpuSize(2*kImageWH) + helper.gpuSize(kImageWH)/2;
1211
1212 auto cache = dContext->priv().getResourceCache();
1213 size_t currentBytes = cache->getResourceBytes();
1214
1215 SkASSERT(currentBytes >= desiredBytes);
1216 size_t amountToPurge = currentBytes - desiredBytes;
1217
1218 // The 2*kImageWH texture should be MRU.
1219 dContext->purgeUnlockedResources(amountToPurge, true);
1220
1221 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
1222
Robert Phillips375e1f62020-10-23 16:13:57 -04001223 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH,
1224 /*hits*/ 2, /*misses*/ 2, /*refs*/ 0, kNoID));
Robert Phillips187b04b2020-09-22 12:18:16 -04001225}
Robert Phillips331699c2020-09-22 15:20:01 -04001226
Robert Phillips375e1f62020-10-23 16:13:57 -04001227DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache10View, reporter, ctxInfo) {
1228 test_10(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
1229}
1230
1231// To enable test_10 with verts would require a bit more work, namely:
1232// have a different # of verts based on size
1233// also pass in a gpuSize function to 'test_10'
1234//DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache10Verts, reporter, ctxInfo) {
1235// test_10(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
1236//}
1237
Robert Phillips331699c2020-09-22 15:20:01 -04001238// Case 11: This checks that scratch-only variant of GrContext::purgeUnlockedResources works as
Robert Phillipsdefd2232020-09-25 15:25:46 -04001239// expected wrt the thread safe cache. In particular, that when 'scratchResourcesOnly'
1240// is true, the call has no effect on the cache.
Robert Phillips375e1f62020-10-23 16:13:57 -04001241static void test_11(GrDirectContext* dContext, skiatest::Reporter* reporter,
1242 TestHelper::addAccessFP addAccess,
1243 TestHelper::checkFP check) {
Robert Phillips331699c2020-09-22 15:20:01 -04001244
1245 TestHelper helper(dContext);
1246
Robert Phillips375e1f62020-10-23 16:13:57 -04001247 (helper.*addAccess)(helper.liveCanvas(), kImageWH, kNoID, false, false);
1248 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
1249 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
Robert Phillips331699c2020-09-22 15:20:01 -04001250
Robert Phillips375e1f62020-10-23 16:13:57 -04001251 (helper.*addAccess)(helper.liveCanvas(), 2*kImageWH, kNoID, false, false);
1252 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH,
1253 /*hits*/ 0, /*misses*/ 2, /*refs*/ 1, kNoID));
Robert Phillips331699c2020-09-22 15:20:01 -04001254
1255 dContext->flush();
1256 dContext->submit(true);
1257
1258 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
Robert Phillips375e1f62020-10-23 16:13:57 -04001259 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
1260 /*hits*/ 0, /*misses*/ 2, /*refs*/ 0, kNoID));
1261 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH,
1262 /*hits*/ 0, /*misses*/ 2, /*refs*/ 0, kNoID));
Robert Phillips331699c2020-09-22 15:20:01 -04001263
1264 // This shouldn't remove anything from the cache
1265 dContext->purgeUnlockedResources(/* scratchResourcesOnly */ true);
1266
1267 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
1268
1269 dContext->purgeUnlockedResources(/* scratchResourcesOnly */ false);
1270
1271 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0);
1272}
1273
Robert Phillips375e1f62020-10-23 16:13:57 -04001274DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache11View, reporter, ctxInfo) {
1275 test_11(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
1276}
1277
1278DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache11Verts, reporter, ctxInfo) {
1279 test_11(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
1280}
1281
Robert Phillipsdefd2232020-09-25 15:25:46 -04001282// Case 12: Test out purges caused by resetting the cache budget to 0. Note that, due to
1283// the how the cache operates (i.e., not directly driven by ref/unrefs) there
1284// needs to be an explicit kick to purge the cache.
Robert Phillips375e1f62020-10-23 16:13:57 -04001285static void test_12(GrDirectContext* dContext, skiatest::Reporter* reporter,
1286 TestHelper::addAccessFP addAccess,
1287 TestHelper::checkFP check) {
Robert Phillips331699c2020-09-22 15:20:01 -04001288
1289 TestHelper helper(dContext);
1290
Robert Phillips375e1f62020-10-23 16:13:57 -04001291 (helper.*addAccess)(helper.liveCanvas(), kImageWH, kNoID, false, false);
1292 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
1293 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
1294 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false);
Robert Phillips331699c2020-09-22 15:20:01 -04001295 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
Robert Phillips375e1f62020-10-23 16:13:57 -04001296 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
1297 /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, kNoID));
Robert Phillips331699c2020-09-22 15:20:01 -04001298
Robert Phillips375e1f62020-10-23 16:13:57 -04001299 (helper.*addAccess)(helper.liveCanvas(), 2*kImageWH, kNoID, false, false);
1300 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH,
1301 /*hits*/ 1, /*misses*/ 2, /*refs*/ 1, kNoID));
Robert Phillips331699c2020-09-22 15:20:01 -04001302
1303 dContext->flush();
1304 dContext->submit(true);
1305
1306 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
Robert Phillips375e1f62020-10-23 16:13:57 -04001307 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH,
1308 /*hits*/ 1, /*misses*/ 2, /*refs*/ 1, kNoID));
1309 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH,
1310 /*hits*/ 1, /*misses*/ 2, /*refs*/ 0, kNoID));
Robert Phillips331699c2020-09-22 15:20:01 -04001311
1312 dContext->setResourceCacheLimit(0);
1313
1314 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
1315
1316 ddl1 = nullptr;
1317
Robert Phillipsdefd2232020-09-25 15:25:46 -04001318 // Explicitly kick off the purge - it won't happen automatically on unref
Robert Phillips331699c2020-09-22 15:20:01 -04001319 dContext->performDeferredCleanup(std::chrono::milliseconds(0));
1320
1321 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0);
1322}
Robert Phillipsc2fe1642020-09-22 17:34:51 -04001323
Robert Phillips375e1f62020-10-23 16:13:57 -04001324DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache12View, reporter, ctxInfo) {
1325 test_12(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
1326}
1327
1328DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache12Verts, reporter, ctxInfo) {
1329 test_12(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
1330}
1331
Robert Phillipsc2fe1642020-09-22 17:34:51 -04001332// Case 13: Test out the 'msNotUsed' parameter to GrContext::performDeferredCleanup.
Robert Phillips375e1f62020-10-23 16:13:57 -04001333static void test_13(GrDirectContext* dContext, skiatest::Reporter* reporter,
1334 TestHelper::addAccessFP addAccess,
1335 TestHelper::checkFP check) {
Robert Phillipsc2fe1642020-09-22 17:34:51 -04001336
1337 TestHelper helper(dContext);
1338
Robert Phillips375e1f62020-10-23 16:13:57 -04001339 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false);
1340 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
1341 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
Robert Phillipsc2fe1642020-09-22 17:34:51 -04001342 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
1343
1344 std::this_thread::sleep_for(std::chrono::milliseconds(5));
1345 auto firstTime = GrStdSteadyClock::now();
1346 std::this_thread::sleep_for(std::chrono::milliseconds(5));
1347
Robert Phillips375e1f62020-10-23 16:13:57 -04001348 (helper.*addAccess)(helper.ddlCanvas2(), 2*kImageWH, kNoID, false, false);
1349
1350 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), 2*kImageWH,
1351 /*hits*/ 0, /*misses*/ 2, /*refs*/ 1, kNoID));
Robert Phillipsc2fe1642020-09-22 17:34:51 -04001352 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
1353
1354 ddl1 = nullptr;
1355 ddl2 = nullptr;
1356
1357 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2);
1358
1359 auto secondTime = GrStdSteadyClock::now();
1360
1361 auto msecs = std::chrono::duration_cast<std::chrono::milliseconds>(secondTime - firstTime);
1362 dContext->performDeferredCleanup(msecs);
1363
1364 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
Robert Phillips375e1f62020-10-23 16:13:57 -04001365 REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH,
1366 /*hits*/ 0, /*misses*/ 2, /*refs*/ 0, kNoID));
1367}
1368
1369DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache13View, reporter, ctxInfo) {
1370 test_13(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView);
1371}
1372
1373DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache13Verts, reporter, ctxInfo) {
1374 test_13(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert);
Robert Phillipsc2fe1642020-09-22 17:34:51 -04001375}
Robert Phillips3ac83b2f2020-10-26 13:50:57 -04001376
1377// Case 14: Test out mixing & matching view & vertex data w/ recycling of the cache entries to
1378// wring out the anonymous union code. This is mainly for the MSAN bot's consumption.
1379DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache14, reporter, ctxInfo) {
1380 constexpr int kBestPrimeNumber = 73; // palindromic in binary
1381 SkRandom rand(kBestPrimeNumber);
1382
1383 TestHelper helper(ctxInfo.directContext());
1384
1385 for (int i = 0; i < 2; ++i) {
1386 SkCanvas* ddlCanvas = (!i) ? helper.ddlCanvas1() : helper.ddlCanvas2();
1387
1388 for (int j = 0; j < 10; ++j) {
1389 int numResources = 10*i + j + 1;
1390 int wh = numResources;
1391
1392 if (rand.nextBool()) {
1393 helper.addViewAccess(ddlCanvas, wh, kNoID, false, false);
1394 REPORTER_ASSERT(reporter, helper.checkView(ddlCanvas, wh,
1395 /*hits*/ 0, /*misses*/ numResources,
1396 /*refs*/ 1, kNoID));
1397 } else {
1398 helper.addVertAccess(ddlCanvas, wh, kNoID, false, false);
1399 REPORTER_ASSERT(reporter, helper.checkVert(ddlCanvas, wh,
1400 /*hits*/ 0, /*misses*/ numResources,
1401 /*refs*/ 1, kNoID));
1402 }
1403 }
1404
1405 if (!i) {
1406 // Drop all the accumulated resources from the thread-safe cache
1407 helper.snap1();
1408 ctxInfo.directContext()->purgeUnlockedResources(/* scratchResourcesOnly */ false);
1409 }
1410 }
1411}
Robert Phillips83c38a82020-10-28 14:57:53 -04001412
1413// Case 15: Test out posting invalidation messages that involve the thread safe cache
1414static void test_15(GrDirectContext* dContext, skiatest::Reporter* reporter,
1415 TestHelper::addAccessFP addAccess,
1416 TestHelper::checkFP check,
1417 void (*create_key)(GrUniqueKey*, int wh, int id)) {
1418
1419 TestHelper helper(dContext);
1420
1421 (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false);
1422 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH,
1423 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
1424 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
1425
1426 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
1427
1428 GrUniqueKey key;
1429 (*create_key)(&key, kImageWH, kNoID);
1430
1431 GrUniqueKeyInvalidatedMessage msg(key, dContext->priv().contextID(),
1432 /* inThreadSafeCache */ true);
1433
1434 SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(msg);
1435
1436 // This purge call is needed to process the invalidation messages
1437 dContext->purgeUnlockedResources(/* scratchResourcesOnly */ true);
1438
1439 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0);
1440
1441 (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, kNoID, false, false);
1442 REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), kImageWH,
1443 /*hits*/ 0, /*misses*/ 2, /*refs*/ 1, kNoID));
1444 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
1445
1446 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
1447
1448 helper.checkImage(reporter, std::move(ddl1));
1449 helper.checkImage(reporter, std::move(ddl2));
1450}
1451
1452DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache15View, reporter, ctxInfo) {
1453 test_15(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView,
1454 create_view_key);
1455}
1456
1457DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache15Verts, reporter, ctxInfo) {
1458 test_15(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert,
1459 create_vert_key);
1460}
Robert Phillips67e58cb2020-11-02 08:57:39 -05001461
1462// Case 16: Test out pre-emption of an existing vertex-data cache entry. This test simulates
1463// the case where there is a race to create vertex data. However, the second one
1464// to finish is better and usurps the first's position in the cache.
1465//
1466// This capability isn't available for views.
1467
1468static bool newer_is_always_better(SkData* /* incumbent */, SkData* /* challenger */) {
1469 return true;
1470};
1471
1472DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache16Verts, reporter, ctxInfo) {
1473 GrUniqueKey key;
1474 create_vert_key(&key, kImageWH, kNoID);
1475
1476 TestHelper helper(ctxInfo.directContext(), newer_is_always_better);
1477
1478 GrThreadSafeVertexTestOp* op1 = nullptr, *op2 = nullptr;
1479
1480 helper.addVertAccess(helper.ddlCanvas1(), kImageWH, kNoID, false, false, &op1);
1481 REPORTER_ASSERT(reporter, helper.checkVert(helper.ddlCanvas1(), kImageWH,
1482 /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID));
1483 sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1();
1484
1485 {
1486 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
1487 auto [vertexData, xtraData] = helper.threadSafeCache()->findVertsWithData(key);
1488 REPORTER_ASSERT(reporter, vertexData.get() == op1->vertexData());
1489 }
1490
1491 helper.addVertAccess(helper.ddlCanvas2(), kImageWH, kNoID, /* failLookup */ true, false, &op2);
1492 REPORTER_ASSERT(reporter, helper.checkVert(helper.ddlCanvas2(), kImageWH,
1493 /*hits*/ 0, /*misses*/ 2, /*refs*/ 1, kNoID));
1494 sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2();
1495
1496 REPORTER_ASSERT(reporter, op1->vertexData() != op2->vertexData());
1497
1498 {
1499 REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1);
1500 auto [vertexData, xtraData] = helper.threadSafeCache()->findVertsWithData(key);
1501 REPORTER_ASSERT(reporter, vertexData.get() == op2->vertexData());
1502 }
1503
1504 helper.checkImage(reporter, std::move(ddl1));
1505 helper.checkImage(reporter, std::move(ddl2));
1506}