1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2020 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 9cb93a386Sopenharmony_ci#include "include/core/SkDeferredDisplayListRecorder.h" 10cb93a386Sopenharmony_ci#include "include/core/SkSurfaceCharacterization.h" 11cb93a386Sopenharmony_ci#include "include/private/SkMalloc.h" 12cb93a386Sopenharmony_ci#include "include/utils/SkRandom.h" 13cb93a386Sopenharmony_ci#include "src/core/SkCanvasPriv.h" 14cb93a386Sopenharmony_ci#include "src/core/SkMessageBus.h" 15cb93a386Sopenharmony_ci#include "src/gpu/GrDefaultGeoProcFactory.h" 16cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h" 17cb93a386Sopenharmony_ci#include "src/gpu/GrGpu.h" 18cb93a386Sopenharmony_ci#include "src/gpu/GrMemoryPool.h" 19cb93a386Sopenharmony_ci#include "src/gpu/GrOpFlushState.h" 20cb93a386Sopenharmony_ci#include "src/gpu/GrProxyProvider.h" 21cb93a386Sopenharmony_ci#include "src/gpu/GrRecordingContextPriv.h" 22cb93a386Sopenharmony_ci#include "src/gpu/GrResourceProvider.h" 23cb93a386Sopenharmony_ci#include "src/gpu/GrStyle.h" 24cb93a386Sopenharmony_ci#include "src/gpu/GrThreadSafeCache.h" 25cb93a386Sopenharmony_ci#include "src/gpu/ops/GrDrawOp.h" 26cb93a386Sopenharmony_ci#include "src/gpu/v1/SurfaceDrawContext_v1.h" 27cb93a386Sopenharmony_ci#include "tests/Test.h" 28cb93a386Sopenharmony_ci#include "tests/TestUtils.h" 29cb93a386Sopenharmony_ci#include "tools/gpu/ProxyUtils.h" 30cb93a386Sopenharmony_ci 31cb93a386Sopenharmony_ci#include <thread> 32cb93a386Sopenharmony_ci 33cb93a386Sopenharmony_cistatic constexpr int kImageWH = 32; 34cb93a386Sopenharmony_cistatic constexpr auto kImageOrigin = kBottomLeft_GrSurfaceOrigin; 35cb93a386Sopenharmony_cistatic constexpr int kNoID = -1; 36cb93a386Sopenharmony_ci 37cb93a386Sopenharmony_cistatic SkImageInfo default_ii(int wh) { 38cb93a386Sopenharmony_ci return SkImageInfo::Make(wh, wh, kRGBA_8888_SkColorType, kPremul_SkAlphaType); 39cb93a386Sopenharmony_ci} 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_cistatic std::unique_ptr<skgpu::v1::SurfaceDrawContext> new_SDC(GrRecordingContext* rContext, 42cb93a386Sopenharmony_ci int wh) { 43cb93a386Sopenharmony_ci return skgpu::v1::SurfaceDrawContext::Make(rContext, 44cb93a386Sopenharmony_ci GrColorType::kRGBA_8888, 45cb93a386Sopenharmony_ci nullptr, 46cb93a386Sopenharmony_ci SkBackingFit::kExact, 47cb93a386Sopenharmony_ci {wh, wh}, 48cb93a386Sopenharmony_ci SkSurfaceProps(), 49cb93a386Sopenharmony_ci 1, 50cb93a386Sopenharmony_ci GrMipMapped::kNo, 51cb93a386Sopenharmony_ci GrProtected::kNo, 52cb93a386Sopenharmony_ci kImageOrigin, 53cb93a386Sopenharmony_ci SkBudgeted::kYes); 54cb93a386Sopenharmony_ci} 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_cistatic void create_view_key(GrUniqueKey* key, int wh, int id) { 57cb93a386Sopenharmony_ci static const GrUniqueKey::Domain kViewDomain = GrUniqueKey::GenerateDomain(); 58cb93a386Sopenharmony_ci GrUniqueKey::Builder builder(key, kViewDomain, 1); 59cb93a386Sopenharmony_ci builder[0] = wh; 60cb93a386Sopenharmony_ci builder.finish(); 61cb93a386Sopenharmony_ci 62cb93a386Sopenharmony_ci if (id != kNoID) { 63cb93a386Sopenharmony_ci key->setCustomData(SkData::MakeWithCopy(&id, sizeof(id))); 64cb93a386Sopenharmony_ci } 65cb93a386Sopenharmony_ci} 66cb93a386Sopenharmony_ci 67cb93a386Sopenharmony_cistatic void create_vert_key(GrUniqueKey* key, int wh, int id) { 68cb93a386Sopenharmony_ci static const GrUniqueKey::Domain kVertDomain = GrUniqueKey::GenerateDomain(); 69cb93a386Sopenharmony_ci GrUniqueKey::Builder builder(key, kVertDomain, 1); 70cb93a386Sopenharmony_ci builder[0] = wh; 71cb93a386Sopenharmony_ci builder.finish(); 72cb93a386Sopenharmony_ci 73cb93a386Sopenharmony_ci if (id != kNoID) { 74cb93a386Sopenharmony_ci key->setCustomData(SkData::MakeWithCopy(&id, sizeof(id))); 75cb93a386Sopenharmony_ci } 76cb93a386Sopenharmony_ci} 77cb93a386Sopenharmony_ci 78cb93a386Sopenharmony_cistatic bool default_is_newer_better(SkData* incumbent, SkData* challenger) { 79cb93a386Sopenharmony_ci return false; 80cb93a386Sopenharmony_ci} 81cb93a386Sopenharmony_ci 82cb93a386Sopenharmony_ci// When testing views we create a bitmap that covers the entire screen and has an inset blue rect 83cb93a386Sopenharmony_ci// atop a field of white. 84cb93a386Sopenharmony_ci// When testing verts we clear the background to white and simply draw an inset blur rect. 85cb93a386Sopenharmony_cistatic SkBitmap create_bitmap(int wh) { 86cb93a386Sopenharmony_ci SkBitmap bitmap; 87cb93a386Sopenharmony_ci 88cb93a386Sopenharmony_ci bitmap.allocPixels(default_ii(wh)); 89cb93a386Sopenharmony_ci 90cb93a386Sopenharmony_ci SkCanvas tmp(bitmap); 91cb93a386Sopenharmony_ci tmp.clear(SK_ColorWHITE); 92cb93a386Sopenharmony_ci 93cb93a386Sopenharmony_ci SkPaint blue; 94cb93a386Sopenharmony_ci blue.setColor(SK_ColorBLUE); 95cb93a386Sopenharmony_ci blue.setAntiAlias(false); 96cb93a386Sopenharmony_ci 97cb93a386Sopenharmony_ci tmp.drawRect({10, 10, wh-10.0f, wh-10.0f}, blue); 98cb93a386Sopenharmony_ci 99cb93a386Sopenharmony_ci bitmap.setImmutable(); 100cb93a386Sopenharmony_ci return bitmap; 101cb93a386Sopenharmony_ci} 102cb93a386Sopenharmony_ci 103cb93a386Sopenharmony_ciclass GrThreadSafeVertexTestOp; 104cb93a386Sopenharmony_ci 105cb93a386Sopenharmony_ciclass TestHelper { 106cb93a386Sopenharmony_cipublic: 107cb93a386Sopenharmony_ci struct Stats { 108cb93a386Sopenharmony_ci int fCacheHits = 0; 109cb93a386Sopenharmony_ci int fCacheMisses = 0; 110cb93a386Sopenharmony_ci 111cb93a386Sopenharmony_ci int fNumSWCreations = 0; 112cb93a386Sopenharmony_ci int fNumLazyCreations = 0; 113cb93a386Sopenharmony_ci int fNumHWCreations = 0; 114cb93a386Sopenharmony_ci }; 115cb93a386Sopenharmony_ci 116cb93a386Sopenharmony_ci TestHelper(GrDirectContext* dContext, 117cb93a386Sopenharmony_ci GrThreadSafeCache::IsNewerBetter isNewerBetter = default_is_newer_better) 118cb93a386Sopenharmony_ci : fDContext(dContext) 119cb93a386Sopenharmony_ci , fIsNewerBetter(isNewerBetter) { 120cb93a386Sopenharmony_ci 121cb93a386Sopenharmony_ci fDst = SkSurface::MakeRenderTarget(dContext, SkBudgeted::kNo, default_ii(kImageWH)); 122cb93a386Sopenharmony_ci SkAssertResult(fDst); 123cb93a386Sopenharmony_ci 124cb93a386Sopenharmony_ci SkSurfaceCharacterization characterization; 125cb93a386Sopenharmony_ci SkAssertResult(fDst->characterize(&characterization)); 126cb93a386Sopenharmony_ci 127cb93a386Sopenharmony_ci fRecorder1 = std::make_unique<SkDeferredDisplayListRecorder>(characterization); 128cb93a386Sopenharmony_ci this->ddlCanvas1()->clear(SkColors::kWhite); 129cb93a386Sopenharmony_ci 130cb93a386Sopenharmony_ci fRecorder2 = std::make_unique<SkDeferredDisplayListRecorder>(characterization); 131cb93a386Sopenharmony_ci this->ddlCanvas2()->clear(SkColors::kWhite); 132cb93a386Sopenharmony_ci 133cb93a386Sopenharmony_ci fDst->getCanvas()->clear(SkColors::kWhite); 134cb93a386Sopenharmony_ci } 135cb93a386Sopenharmony_ci 136cb93a386Sopenharmony_ci ~TestHelper() { 137cb93a386Sopenharmony_ci fDContext->flush(); 138cb93a386Sopenharmony_ci fDContext->submit(true); 139cb93a386Sopenharmony_ci } 140cb93a386Sopenharmony_ci 141cb93a386Sopenharmony_ci Stats* stats() { return &fStats; } 142cb93a386Sopenharmony_ci 143cb93a386Sopenharmony_ci int numCacheEntries() const { return this->threadSafeCache()->numEntries(); } 144cb93a386Sopenharmony_ci 145cb93a386Sopenharmony_ci GrDirectContext* dContext() { return fDContext; } 146cb93a386Sopenharmony_ci 147cb93a386Sopenharmony_ci SkCanvas* liveCanvas() { return fDst ? fDst->getCanvas() : nullptr; } 148cb93a386Sopenharmony_ci SkCanvas* ddlCanvas1() { return fRecorder1 ? fRecorder1->getCanvas() : nullptr; } 149cb93a386Sopenharmony_ci sk_sp<SkDeferredDisplayList> snap1() { 150cb93a386Sopenharmony_ci if (fRecorder1) { 151cb93a386Sopenharmony_ci sk_sp<SkDeferredDisplayList> tmp = fRecorder1->detach(); 152cb93a386Sopenharmony_ci fRecorder1 = nullptr; 153cb93a386Sopenharmony_ci return tmp; 154cb93a386Sopenharmony_ci } 155cb93a386Sopenharmony_ci 156cb93a386Sopenharmony_ci return nullptr; 157cb93a386Sopenharmony_ci } 158cb93a386Sopenharmony_ci SkCanvas* ddlCanvas2() { return fRecorder2 ? fRecorder2->getCanvas() : nullptr; } 159cb93a386Sopenharmony_ci sk_sp<SkDeferredDisplayList> snap2() { 160cb93a386Sopenharmony_ci if (fRecorder2) { 161cb93a386Sopenharmony_ci sk_sp<SkDeferredDisplayList> tmp = fRecorder2->detach(); 162cb93a386Sopenharmony_ci fRecorder2 = nullptr; 163cb93a386Sopenharmony_ci return tmp; 164cb93a386Sopenharmony_ci } 165cb93a386Sopenharmony_ci 166cb93a386Sopenharmony_ci return nullptr; 167cb93a386Sopenharmony_ci } 168cb93a386Sopenharmony_ci 169cb93a386Sopenharmony_ci GrThreadSafeCache* threadSafeCache() { return fDContext->priv().threadSafeCache(); } 170cb93a386Sopenharmony_ci const GrThreadSafeCache* threadSafeCache() const { return fDContext->priv().threadSafeCache(); } 171cb93a386Sopenharmony_ci 172cb93a386Sopenharmony_ci typedef void (TestHelper::*addAccessFP)(SkCanvas*, int wh, int id, 173cb93a386Sopenharmony_ci bool failLookUp, bool failFillingIn); 174cb93a386Sopenharmony_ci typedef bool (TestHelper::*checkFP)(SkCanvas*, int wh, 175cb93a386Sopenharmony_ci int expectedHits, int expectedMisses, 176cb93a386Sopenharmony_ci int expectedNumRefs, int expectedID); 177cb93a386Sopenharmony_ci 178cb93a386Sopenharmony_ci // Add a draw on 'canvas' that will introduce a ref on the 'wh' view 179cb93a386Sopenharmony_ci void addViewAccess(SkCanvas* canvas, 180cb93a386Sopenharmony_ci int wh, 181cb93a386Sopenharmony_ci int id = kNoID, 182cb93a386Sopenharmony_ci bool failLookup = false, 183cb93a386Sopenharmony_ci bool failFillingIn = false) { 184cb93a386Sopenharmony_ci auto rContext = canvas->recordingContext(); 185cb93a386Sopenharmony_ci 186cb93a386Sopenharmony_ci auto view = AccessCachedView(rContext, this->threadSafeCache(), 187cb93a386Sopenharmony_ci wh, failLookup, failFillingIn, id, &fStats); 188cb93a386Sopenharmony_ci SkASSERT(view); 189cb93a386Sopenharmony_ci 190cb93a386Sopenharmony_ci auto sdc = SkCanvasPriv::TopDeviceSurfaceDrawContext(canvas); 191cb93a386Sopenharmony_ci 192cb93a386Sopenharmony_ci sdc->drawTexture(nullptr, 193cb93a386Sopenharmony_ci view, 194cb93a386Sopenharmony_ci kPremul_SkAlphaType, 195cb93a386Sopenharmony_ci GrSamplerState::Filter::kNearest, 196cb93a386Sopenharmony_ci GrSamplerState::MipmapMode::kNone, 197cb93a386Sopenharmony_ci SkBlendMode::kSrcOver, 198cb93a386Sopenharmony_ci {1.0f, 1.0f, 1.0f, 1.0f}, 199cb93a386Sopenharmony_ci SkRect::MakeWH(wh, wh), 200cb93a386Sopenharmony_ci SkRect::MakeWH(wh, wh), 201cb93a386Sopenharmony_ci GrAA::kNo, 202cb93a386Sopenharmony_ci GrQuadAAFlags::kNone, 203cb93a386Sopenharmony_ci SkCanvas::kFast_SrcRectConstraint, 204cb93a386Sopenharmony_ci SkMatrix::I(), 205cb93a386Sopenharmony_ci nullptr); 206cb93a386Sopenharmony_ci } 207cb93a386Sopenharmony_ci 208cb93a386Sopenharmony_ci // Besides checking that the number of refs and cache hits and misses are as expected, this 209cb93a386Sopenharmony_ci // method also validates that the unique key doesn't appear in any of the other caches. 210cb93a386Sopenharmony_ci bool checkView(SkCanvas* canvas, int wh, 211cb93a386Sopenharmony_ci int expectedHits, int expectedMisses, int expectedNumRefs, int expectedID) { 212cb93a386Sopenharmony_ci if (fStats.fCacheHits != expectedHits || fStats.fCacheMisses != expectedMisses) { 213cb93a386Sopenharmony_ci SkDebugf("Hits E: %d A: %d --- Misses E: %d A: %d\n", 214cb93a386Sopenharmony_ci expectedHits, fStats.fCacheHits, expectedMisses, fStats.fCacheMisses); 215cb93a386Sopenharmony_ci return false; 216cb93a386Sopenharmony_ci } 217cb93a386Sopenharmony_ci 218cb93a386Sopenharmony_ci GrUniqueKey key; 219cb93a386Sopenharmony_ci create_view_key(&key, wh, kNoID); 220cb93a386Sopenharmony_ci 221cb93a386Sopenharmony_ci auto threadSafeCache = this->threadSafeCache(); 222cb93a386Sopenharmony_ci 223cb93a386Sopenharmony_ci auto [view, xtraData] = threadSafeCache->findWithData(key); 224cb93a386Sopenharmony_ci if (!view.proxy()) { 225cb93a386Sopenharmony_ci return false; 226cb93a386Sopenharmony_ci } 227cb93a386Sopenharmony_ci 228cb93a386Sopenharmony_ci if (expectedID < 0) { 229cb93a386Sopenharmony_ci if (xtraData) { 230cb93a386Sopenharmony_ci return false; 231cb93a386Sopenharmony_ci } 232cb93a386Sopenharmony_ci } else { 233cb93a386Sopenharmony_ci if (!xtraData) { 234cb93a386Sopenharmony_ci return false; 235cb93a386Sopenharmony_ci } 236cb93a386Sopenharmony_ci 237cb93a386Sopenharmony_ci const int* cachedID = static_cast<const int*>(xtraData->data()); 238cb93a386Sopenharmony_ci if (*cachedID != expectedID) { 239cb93a386Sopenharmony_ci return false; 240cb93a386Sopenharmony_ci } 241cb93a386Sopenharmony_ci } 242cb93a386Sopenharmony_ci 243cb93a386Sopenharmony_ci if (!view.proxy()->refCntGreaterThan(expectedNumRefs+1) || // +1 for 'view's ref 244cb93a386Sopenharmony_ci view.proxy()->refCntGreaterThan(expectedNumRefs+2)) { 245cb93a386Sopenharmony_ci return false; 246cb93a386Sopenharmony_ci } 247cb93a386Sopenharmony_ci 248cb93a386Sopenharmony_ci if (canvas) { 249cb93a386Sopenharmony_ci GrRecordingContext* rContext = canvas->recordingContext(); 250cb93a386Sopenharmony_ci GrProxyProvider* recordingProxyProvider = rContext->priv().proxyProvider(); 251cb93a386Sopenharmony_ci sk_sp<GrTextureProxy> result = recordingProxyProvider->findProxyByUniqueKey(key); 252cb93a386Sopenharmony_ci if (result) { 253cb93a386Sopenharmony_ci // views in this cache should never appear in the recorder's cache 254cb93a386Sopenharmony_ci return false; 255cb93a386Sopenharmony_ci } 256cb93a386Sopenharmony_ci } 257cb93a386Sopenharmony_ci 258cb93a386Sopenharmony_ci { 259cb93a386Sopenharmony_ci GrProxyProvider* directProxyProvider = fDContext->priv().proxyProvider(); 260cb93a386Sopenharmony_ci sk_sp<GrTextureProxy> result = directProxyProvider->findProxyByUniqueKey(key); 261cb93a386Sopenharmony_ci if (result) { 262cb93a386Sopenharmony_ci // views in this cache should never appear in the main proxy cache 263cb93a386Sopenharmony_ci return false; 264cb93a386Sopenharmony_ci } 265cb93a386Sopenharmony_ci } 266cb93a386Sopenharmony_ci 267cb93a386Sopenharmony_ci { 268cb93a386Sopenharmony_ci auto resourceProvider = fDContext->priv().resourceProvider(); 269cb93a386Sopenharmony_ci sk_sp<GrSurface> surf = resourceProvider->findByUniqueKey<GrSurface>(key); 270cb93a386Sopenharmony_ci if (surf) { 271cb93a386Sopenharmony_ci // the textures backing the views in this cache should never be discoverable in the 272cb93a386Sopenharmony_ci // resource cache 273cb93a386Sopenharmony_ci return false; 274cb93a386Sopenharmony_ci } 275cb93a386Sopenharmony_ci } 276cb93a386Sopenharmony_ci 277cb93a386Sopenharmony_ci return true; 278cb93a386Sopenharmony_ci } 279cb93a386Sopenharmony_ci 280cb93a386Sopenharmony_ci void addVertAccess(SkCanvas* canvas, 281cb93a386Sopenharmony_ci int wh, 282cb93a386Sopenharmony_ci int id, 283cb93a386Sopenharmony_ci bool failLookup, 284cb93a386Sopenharmony_ci bool failFillingIn, 285cb93a386Sopenharmony_ci GrThreadSafeVertexTestOp** createdOp); 286cb93a386Sopenharmony_ci 287cb93a386Sopenharmony_ci // Add a draw on 'canvas' that will introduce a ref on a 'wh' vertex data 288cb93a386Sopenharmony_ci void addVertAccess(SkCanvas* canvas, 289cb93a386Sopenharmony_ci int wh, 290cb93a386Sopenharmony_ci int id = kNoID, 291cb93a386Sopenharmony_ci bool failLookup = false, 292cb93a386Sopenharmony_ci bool failFillingIn = false) { 293cb93a386Sopenharmony_ci this->addVertAccess(canvas, wh, id, failLookup, failFillingIn, nullptr); 294cb93a386Sopenharmony_ci } 295cb93a386Sopenharmony_ci 296cb93a386Sopenharmony_ci bool checkVert(SkCanvas* canvas, int wh, 297cb93a386Sopenharmony_ci int expectedHits, int expectedMisses, int expectedNumRefs, int expectedID) { 298cb93a386Sopenharmony_ci if (fStats.fCacheHits != expectedHits || fStats.fCacheMisses != expectedMisses) { 299cb93a386Sopenharmony_ci SkDebugf("Hits E: %d A: %d --- Misses E: %d A: %d\n", 300cb93a386Sopenharmony_ci expectedHits, fStats.fCacheHits, expectedMisses, fStats.fCacheMisses); 301cb93a386Sopenharmony_ci return false; 302cb93a386Sopenharmony_ci } 303cb93a386Sopenharmony_ci 304cb93a386Sopenharmony_ci GrUniqueKey key; 305cb93a386Sopenharmony_ci create_vert_key(&key, wh, kNoID); 306cb93a386Sopenharmony_ci 307cb93a386Sopenharmony_ci auto threadSafeCache = this->threadSafeCache(); 308cb93a386Sopenharmony_ci 309cb93a386Sopenharmony_ci auto [vertData, xtraData] = threadSafeCache->findVertsWithData(key); 310cb93a386Sopenharmony_ci if (!vertData) { 311cb93a386Sopenharmony_ci return false; 312cb93a386Sopenharmony_ci } 313cb93a386Sopenharmony_ci 314cb93a386Sopenharmony_ci if (expectedID < 0) { 315cb93a386Sopenharmony_ci if (xtraData) { 316cb93a386Sopenharmony_ci return false; 317cb93a386Sopenharmony_ci } 318cb93a386Sopenharmony_ci } else { 319cb93a386Sopenharmony_ci if (!xtraData) { 320cb93a386Sopenharmony_ci return false; 321cb93a386Sopenharmony_ci } 322cb93a386Sopenharmony_ci 323cb93a386Sopenharmony_ci const int* cachedID = static_cast<const int*>(xtraData->data()); 324cb93a386Sopenharmony_ci if (*cachedID != expectedID) { 325cb93a386Sopenharmony_ci return false; 326cb93a386Sopenharmony_ci } 327cb93a386Sopenharmony_ci } 328cb93a386Sopenharmony_ci 329cb93a386Sopenharmony_ci if (!vertData->refCntGreaterThan(expectedNumRefs+1) || // +1 for 'vertData's ref 330cb93a386Sopenharmony_ci vertData->refCntGreaterThan(expectedNumRefs+2)) { 331cb93a386Sopenharmony_ci return false; 332cb93a386Sopenharmony_ci } 333cb93a386Sopenharmony_ci 334cb93a386Sopenharmony_ci { 335cb93a386Sopenharmony_ci auto resourceProvider = fDContext->priv().resourceProvider(); 336cb93a386Sopenharmony_ci sk_sp<GrGpuBuffer> buffer = resourceProvider->findByUniqueKey<GrGpuBuffer>(key); 337cb93a386Sopenharmony_ci if (buffer) { 338cb93a386Sopenharmony_ci // the buffer holding the vertex data in this cache should never be discoverable 339cb93a386Sopenharmony_ci // in the resource cache 340cb93a386Sopenharmony_ci return false; 341cb93a386Sopenharmony_ci } 342cb93a386Sopenharmony_ci } 343cb93a386Sopenharmony_ci 344cb93a386Sopenharmony_ci return true; 345cb93a386Sopenharmony_ci } 346cb93a386Sopenharmony_ci 347cb93a386Sopenharmony_ci bool checkImage(skiatest::Reporter* reporter, sk_sp<SkSurface> s) { 348cb93a386Sopenharmony_ci SkBitmap actual; 349cb93a386Sopenharmony_ci 350cb93a386Sopenharmony_ci actual.allocPixels(default_ii(kImageWH)); 351cb93a386Sopenharmony_ci 352cb93a386Sopenharmony_ci if (!s->readPixels(actual, 0, 0)) { 353cb93a386Sopenharmony_ci return false; 354cb93a386Sopenharmony_ci } 355cb93a386Sopenharmony_ci 356cb93a386Sopenharmony_ci SkBitmap expected = create_bitmap(kImageWH); 357cb93a386Sopenharmony_ci 358cb93a386Sopenharmony_ci const float tols[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; 359cb93a386Sopenharmony_ci 360cb93a386Sopenharmony_ci auto error = std::function<ComparePixmapsErrorReporter>( 361cb93a386Sopenharmony_ci [reporter](int x, int y, const float diffs[4]) { 362cb93a386Sopenharmony_ci SkASSERT(x >= 0 && y >= 0); 363cb93a386Sopenharmony_ci ERRORF(reporter, "mismatch at %d, %d (%f, %f, %f %f)", 364cb93a386Sopenharmony_ci x, y, diffs[0], diffs[1], diffs[2], diffs[3]); 365cb93a386Sopenharmony_ci }); 366cb93a386Sopenharmony_ci 367cb93a386Sopenharmony_ci return ComparePixels(expected.pixmap(), actual.pixmap(), tols, error); 368cb93a386Sopenharmony_ci } 369cb93a386Sopenharmony_ci 370cb93a386Sopenharmony_ci bool checkImage(skiatest::Reporter* reporter) { 371cb93a386Sopenharmony_ci return this->checkImage(reporter, fDst); 372cb93a386Sopenharmony_ci } 373cb93a386Sopenharmony_ci 374cb93a386Sopenharmony_ci bool checkImage(skiatest::Reporter* reporter, sk_sp<SkDeferredDisplayList> ddl) { 375cb93a386Sopenharmony_ci sk_sp<SkSurface> tmp = SkSurface::MakeRenderTarget(fDContext, 376cb93a386Sopenharmony_ci SkBudgeted::kNo, 377cb93a386Sopenharmony_ci default_ii(kImageWH)); 378cb93a386Sopenharmony_ci if (!tmp) { 379cb93a386Sopenharmony_ci return false; 380cb93a386Sopenharmony_ci } 381cb93a386Sopenharmony_ci 382cb93a386Sopenharmony_ci if (!tmp->draw(std::move(ddl))) { 383cb93a386Sopenharmony_ci return false; 384cb93a386Sopenharmony_ci } 385cb93a386Sopenharmony_ci 386cb93a386Sopenharmony_ci return this->checkImage(reporter, std::move(tmp)); 387cb93a386Sopenharmony_ci } 388cb93a386Sopenharmony_ci 389cb93a386Sopenharmony_ci size_t gpuSize(int wh) const { 390cb93a386Sopenharmony_ci GrBackendFormat format = fDContext->defaultBackendFormat(kRGBA_8888_SkColorType, 391cb93a386Sopenharmony_ci GrRenderable::kNo); 392cb93a386Sopenharmony_ci 393cb93a386Sopenharmony_ci return GrSurface::ComputeSize(format, {wh, wh}, /*colorSamplesPerPixel=*/1, 394cb93a386Sopenharmony_ci GrMipMapped::kNo, /*binSize=*/false); 395cb93a386Sopenharmony_ci } 396cb93a386Sopenharmony_ci 397cb93a386Sopenharmony_ciprivate: 398cb93a386Sopenharmony_ci static GrSurfaceProxyView AccessCachedView(GrRecordingContext*, 399cb93a386Sopenharmony_ci GrThreadSafeCache*, 400cb93a386Sopenharmony_ci int wh, 401cb93a386Sopenharmony_ci bool failLookup, bool failFillingIn, int id, 402cb93a386Sopenharmony_ci Stats*); 403cb93a386Sopenharmony_ci static GrSurfaceProxyView CreateViewOnCpu(GrRecordingContext*, int wh, Stats*); 404cb93a386Sopenharmony_ci static bool FillInViewOnGpu(GrDirectContext*, int wh, Stats*, 405cb93a386Sopenharmony_ci const GrSurfaceProxyView& lazyView, 406cb93a386Sopenharmony_ci sk_sp<GrThreadSafeCache::Trampoline>); 407cb93a386Sopenharmony_ci 408cb93a386Sopenharmony_ci Stats fStats; 409cb93a386Sopenharmony_ci GrDirectContext* fDContext = nullptr; 410cb93a386Sopenharmony_ci GrThreadSafeCache::IsNewerBetter fIsNewerBetter; 411cb93a386Sopenharmony_ci 412cb93a386Sopenharmony_ci sk_sp<SkSurface> fDst; 413cb93a386Sopenharmony_ci std::unique_ptr<SkDeferredDisplayListRecorder> fRecorder1; 414cb93a386Sopenharmony_ci std::unique_ptr<SkDeferredDisplayListRecorder> fRecorder2; 415cb93a386Sopenharmony_ci}; 416cb93a386Sopenharmony_ci 417cb93a386Sopenharmony_ciclass GrThreadSafeVertexTestOp : public GrDrawOp { 418cb93a386Sopenharmony_cipublic: 419cb93a386Sopenharmony_ci DEFINE_OP_CLASS_ID 420cb93a386Sopenharmony_ci 421cb93a386Sopenharmony_ci static GrOp::Owner Make(GrRecordingContext* rContext, TestHelper::Stats* stats, 422cb93a386Sopenharmony_ci int wh, int id, bool failLookup, bool failFillingIn, 423cb93a386Sopenharmony_ci GrThreadSafeCache::IsNewerBetter isNewerBetter) { 424cb93a386Sopenharmony_ci 425cb93a386Sopenharmony_ci return GrOp::Make<GrThreadSafeVertexTestOp>( 426cb93a386Sopenharmony_ci rContext, rContext, stats, wh, id, failLookup, failFillingIn, isNewerBetter); 427cb93a386Sopenharmony_ci } 428cb93a386Sopenharmony_ci 429cb93a386Sopenharmony_ci const GrThreadSafeCache::VertexData* vertexData() const { return fVertexData.get(); } 430cb93a386Sopenharmony_ci 431cb93a386Sopenharmony_ciprivate: 432cb93a386Sopenharmony_ci friend class GrOp; // for ctor 433cb93a386Sopenharmony_ci 434cb93a386Sopenharmony_ci GrThreadSafeVertexTestOp(GrRecordingContext* rContext, TestHelper::Stats* stats, int wh, int id, 435cb93a386Sopenharmony_ci bool failLookup, bool failFillingIn, 436cb93a386Sopenharmony_ci GrThreadSafeCache::IsNewerBetter isNewerBetter) 437cb93a386Sopenharmony_ci : INHERITED(ClassID()) 438cb93a386Sopenharmony_ci , fStats(stats) 439cb93a386Sopenharmony_ci , fWH(wh) 440cb93a386Sopenharmony_ci , fID(id) 441cb93a386Sopenharmony_ci , fFailFillingIn(failFillingIn) 442cb93a386Sopenharmony_ci , fIsNewerBetter(isNewerBetter) { 443cb93a386Sopenharmony_ci this->setBounds(SkRect::MakeIWH(fWH, fWH), HasAABloat::kNo, IsHairline::kNo); 444cb93a386Sopenharmony_ci 445cb93a386Sopenharmony_ci // Normally we wouldn't add a ref to the vertex data at this point. However, it is 446cb93a386Sopenharmony_ci // needed in this unit test to get the ref counts on the uniquely keyed resources 447cb93a386Sopenharmony_ci // to be as expected. 448cb93a386Sopenharmony_ci this->findOrCreateVertices(rContext, failLookup, fFailFillingIn); 449cb93a386Sopenharmony_ci } 450cb93a386Sopenharmony_ci 451cb93a386Sopenharmony_ci const char* name() const override { return "GrThreadSafeVertexTestOp"; } 452cb93a386Sopenharmony_ci FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; } 453cb93a386Sopenharmony_ci GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override { 454cb93a386Sopenharmony_ci return GrProcessorSet::EmptySetAnalysis(); 455cb93a386Sopenharmony_ci } 456cb93a386Sopenharmony_ci 457cb93a386Sopenharmony_ci GrProgramInfo* createProgramInfo(const GrCaps* caps, 458cb93a386Sopenharmony_ci SkArenaAlloc* arena, 459cb93a386Sopenharmony_ci const GrSurfaceProxyView& writeView, 460cb93a386Sopenharmony_ci bool usesMSAASurface, 461cb93a386Sopenharmony_ci GrAppliedClip&& appliedClip, 462cb93a386Sopenharmony_ci const GrDstProxyView& dstProxyView, 463cb93a386Sopenharmony_ci GrXferBarrierFlags renderPassXferBarriers, 464cb93a386Sopenharmony_ci GrLoadOp colorLoadOp) const { 465cb93a386Sopenharmony_ci using namespace GrDefaultGeoProcFactory; 466cb93a386Sopenharmony_ci 467cb93a386Sopenharmony_ci Color color({ 0.0f, 0.0f, 1.0f, 1.0f }); 468cb93a386Sopenharmony_ci 469cb93a386Sopenharmony_ci auto gp = MakeForDeviceSpace(arena, color, 470cb93a386Sopenharmony_ci Coverage::kSolid_Type, 471cb93a386Sopenharmony_ci LocalCoords::kUnused_Type, 472cb93a386Sopenharmony_ci SkMatrix::I()); 473cb93a386Sopenharmony_ci 474cb93a386Sopenharmony_ci return sk_gpu_test::CreateProgramInfo(caps, arena, writeView, usesMSAASurface, 475cb93a386Sopenharmony_ci std::move(appliedClip), dstProxyView, 476cb93a386Sopenharmony_ci gp, SkBlendMode::kSrcOver, 477cb93a386Sopenharmony_ci GrPrimitiveType::kTriangleStrip, 478cb93a386Sopenharmony_ci renderPassXferBarriers, colorLoadOp); 479cb93a386Sopenharmony_ci } 480cb93a386Sopenharmony_ci 481cb93a386Sopenharmony_ci GrProgramInfo* createProgramInfo(GrOpFlushState* flushState) const { 482cb93a386Sopenharmony_ci return this->createProgramInfo(&flushState->caps(), 483cb93a386Sopenharmony_ci flushState->allocator(), 484cb93a386Sopenharmony_ci flushState->writeView(), 485cb93a386Sopenharmony_ci flushState->usesMSAASurface(), 486cb93a386Sopenharmony_ci flushState->detachAppliedClip(), 487cb93a386Sopenharmony_ci flushState->dstProxyView(), 488cb93a386Sopenharmony_ci flushState->renderPassBarriers(), 489cb93a386Sopenharmony_ci flushState->colorLoadOp()); 490cb93a386Sopenharmony_ci } 491cb93a386Sopenharmony_ci 492cb93a386Sopenharmony_ci void findOrCreateVertices(GrRecordingContext* rContext, bool failLookup, bool failFillingIn) { 493cb93a386Sopenharmony_ci 494cb93a386Sopenharmony_ci if (!fVertexData) { 495cb93a386Sopenharmony_ci auto threadSafeViewCache = rContext->priv().threadSafeCache(); 496cb93a386Sopenharmony_ci 497cb93a386Sopenharmony_ci if (rContext->asDirectContext()) { 498cb93a386Sopenharmony_ci // The vertex variant doesn't have a correlate to lazyProxies but increment this 499cb93a386Sopenharmony_ci // here to make the unit tests happy. 500cb93a386Sopenharmony_ci ++fStats->fNumLazyCreations; 501cb93a386Sopenharmony_ci } 502cb93a386Sopenharmony_ci 503cb93a386Sopenharmony_ci GrUniqueKey key; 504cb93a386Sopenharmony_ci create_vert_key(&key, fWH, fID); 505cb93a386Sopenharmony_ci 506cb93a386Sopenharmony_ci // We can "fail the lookup" to simulate a threaded race condition 507cb93a386Sopenharmony_ci auto [cachedVerts, data] = threadSafeViewCache->findVertsWithData(key); 508cb93a386Sopenharmony_ci if (cachedVerts && !failLookup) { 509cb93a386Sopenharmony_ci fVertexData = cachedVerts; 510cb93a386Sopenharmony_ci ++fStats->fCacheHits; 511cb93a386Sopenharmony_ci return; 512cb93a386Sopenharmony_ci } 513cb93a386Sopenharmony_ci 514cb93a386Sopenharmony_ci ++fStats->fCacheMisses; 515cb93a386Sopenharmony_ci if (!rContext->asDirectContext()) { 516cb93a386Sopenharmony_ci ++fStats->fNumSWCreations; 517cb93a386Sopenharmony_ci } 518cb93a386Sopenharmony_ci 519cb93a386Sopenharmony_ci constexpr size_t kVertSize = sizeof(SkPoint); 520cb93a386Sopenharmony_ci SkPoint* verts = static_cast<SkPoint*>(sk_malloc_throw(4 * kVertSize)); 521cb93a386Sopenharmony_ci 522cb93a386Sopenharmony_ci verts[0].set(10.0f, 10.0f); 523cb93a386Sopenharmony_ci verts[1].set(fWH-10.0f, 10.0f); 524cb93a386Sopenharmony_ci verts[2].set(10.0f, fWH-10.0f); 525cb93a386Sopenharmony_ci verts[3].set(fWH-10.0f, fWH-10.0f); 526cb93a386Sopenharmony_ci 527cb93a386Sopenharmony_ci fVertexData = GrThreadSafeCache::MakeVertexData(verts, 4, kVertSize); 528cb93a386Sopenharmony_ci 529cb93a386Sopenharmony_ci auto [tmpV, tmpD] = threadSafeViewCache->addVertsWithData(key, fVertexData, 530cb93a386Sopenharmony_ci fIsNewerBetter); 531cb93a386Sopenharmony_ci if (tmpV != fVertexData) { 532cb93a386Sopenharmony_ci // Someone beat us to creating the vertex data. Use that version. 533cb93a386Sopenharmony_ci fVertexData = tmpV; 534cb93a386Sopenharmony_ci } 535cb93a386Sopenharmony_ci } 536cb93a386Sopenharmony_ci 537cb93a386Sopenharmony_ci if (auto dContext = rContext->asDirectContext(); dContext && !fVertexData->gpuBuffer()) { 538cb93a386Sopenharmony_ci auto rp = dContext->priv().resourceProvider(); 539cb93a386Sopenharmony_ci 540cb93a386Sopenharmony_ci if (!failFillingIn) { 541cb93a386Sopenharmony_ci ++fStats->fNumHWCreations; 542cb93a386Sopenharmony_ci 543cb93a386Sopenharmony_ci sk_sp<GrGpuBuffer> tmp = rp->createBuffer(fVertexData->size(), 544cb93a386Sopenharmony_ci GrGpuBufferType::kVertex, 545cb93a386Sopenharmony_ci kStatic_GrAccessPattern, 546cb93a386Sopenharmony_ci fVertexData->vertices()); 547cb93a386Sopenharmony_ci fVertexData->setGpuBuffer(std::move(tmp)); 548cb93a386Sopenharmony_ci } 549cb93a386Sopenharmony_ci } 550cb93a386Sopenharmony_ci } 551cb93a386Sopenharmony_ci 552cb93a386Sopenharmony_ci void onPrePrepare(GrRecordingContext* rContext, 553cb93a386Sopenharmony_ci const GrSurfaceProxyView& writeView, 554cb93a386Sopenharmony_ci GrAppliedClip* clip, 555cb93a386Sopenharmony_ci const GrDstProxyView& dstProxyView, 556cb93a386Sopenharmony_ci GrXferBarrierFlags renderPassXferBarriers, 557cb93a386Sopenharmony_ci GrLoadOp colorLoadOp) override { 558cb93a386Sopenharmony_ci SkArenaAlloc* arena = rContext->priv().recordTimeAllocator(); 559cb93a386Sopenharmony_ci 560cb93a386Sopenharmony_ci // DMSAA is not supported on DDL. 561cb93a386Sopenharmony_ci bool usesMSAASurface = writeView.asRenderTargetProxy()->numSamples() > 1; 562cb93a386Sopenharmony_ci 563cb93a386Sopenharmony_ci // This is equivalent to a GrOpFlushState::detachAppliedClip 564cb93a386Sopenharmony_ci GrAppliedClip appliedClip = clip ? std::move(*clip) : GrAppliedClip::Disabled(); 565cb93a386Sopenharmony_ci 566cb93a386Sopenharmony_ci fProgramInfo = this->createProgramInfo(rContext->priv().caps(), arena, writeView, 567cb93a386Sopenharmony_ci usesMSAASurface, std::move(appliedClip), 568cb93a386Sopenharmony_ci dstProxyView, renderPassXferBarriers, colorLoadOp); 569cb93a386Sopenharmony_ci 570cb93a386Sopenharmony_ci rContext->priv().recordProgramInfo(fProgramInfo); 571cb93a386Sopenharmony_ci 572cb93a386Sopenharmony_ci // This is now a noop (bc it is always called in the ctor) but is where we would normally 573cb93a386Sopenharmony_ci // create the vertices. 574cb93a386Sopenharmony_ci this->findOrCreateVertices(rContext, false, fFailFillingIn); 575cb93a386Sopenharmony_ci } 576cb93a386Sopenharmony_ci 577cb93a386Sopenharmony_ci void onPrepare(GrOpFlushState* flushState) override { 578cb93a386Sopenharmony_ci auto dContext = flushState->gpu()->getContext(); 579cb93a386Sopenharmony_ci 580cb93a386Sopenharmony_ci // This call site is not a noop bc this op could've been created on with DDL context 581cb93a386Sopenharmony_ci // and, therefore, could be lacking a gpu-side buffer 582cb93a386Sopenharmony_ci this->findOrCreateVertices(dContext, false, fFailFillingIn); 583cb93a386Sopenharmony_ci } 584cb93a386Sopenharmony_ci 585cb93a386Sopenharmony_ci void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override { 586cb93a386Sopenharmony_ci if (!fVertexData || !fVertexData->gpuBuffer()) { 587cb93a386Sopenharmony_ci return; 588cb93a386Sopenharmony_ci } 589cb93a386Sopenharmony_ci 590cb93a386Sopenharmony_ci if (!fProgramInfo) { 591cb93a386Sopenharmony_ci fProgramInfo = this->createProgramInfo(flushState); 592cb93a386Sopenharmony_ci } 593cb93a386Sopenharmony_ci 594cb93a386Sopenharmony_ci flushState->bindPipeline(*fProgramInfo, SkRect::MakeIWH(fWH, fWH)); 595cb93a386Sopenharmony_ci flushState->bindBuffers(nullptr, nullptr, fVertexData->refGpuBuffer()); 596cb93a386Sopenharmony_ci flushState->draw(4, 0); 597cb93a386Sopenharmony_ci } 598cb93a386Sopenharmony_ci 599cb93a386Sopenharmony_ci TestHelper::Stats* fStats; 600cb93a386Sopenharmony_ci int fWH; 601cb93a386Sopenharmony_ci int fID; 602cb93a386Sopenharmony_ci bool fFailFillingIn; 603cb93a386Sopenharmony_ci GrThreadSafeCache::IsNewerBetter fIsNewerBetter; 604cb93a386Sopenharmony_ci 605cb93a386Sopenharmony_ci sk_sp<GrThreadSafeCache::VertexData> fVertexData; 606cb93a386Sopenharmony_ci GrProgramInfo* fProgramInfo = nullptr; 607cb93a386Sopenharmony_ci 608cb93a386Sopenharmony_ci using INHERITED = GrDrawOp; 609cb93a386Sopenharmony_ci}; 610cb93a386Sopenharmony_ci 611cb93a386Sopenharmony_civoid TestHelper::addVertAccess(SkCanvas* canvas, 612cb93a386Sopenharmony_ci int wh, int id, 613cb93a386Sopenharmony_ci bool failLookup, bool failFillingIn, 614cb93a386Sopenharmony_ci GrThreadSafeVertexTestOp** createdOp) { 615cb93a386Sopenharmony_ci auto rContext = canvas->recordingContext(); 616cb93a386Sopenharmony_ci auto sdc = SkCanvasPriv::TopDeviceSurfaceDrawContext(canvas); 617cb93a386Sopenharmony_ci 618cb93a386Sopenharmony_ci GrOp::Owner op = GrThreadSafeVertexTestOp::Make(rContext, &fStats, 619cb93a386Sopenharmony_ci wh, id, 620cb93a386Sopenharmony_ci failLookup, failFillingIn, 621cb93a386Sopenharmony_ci fIsNewerBetter); 622cb93a386Sopenharmony_ci if (createdOp) { 623cb93a386Sopenharmony_ci *createdOp = (GrThreadSafeVertexTestOp*) op.get(); 624cb93a386Sopenharmony_ci } 625cb93a386Sopenharmony_ci 626cb93a386Sopenharmony_ci sdc->addDrawOp(std::move(op)); 627cb93a386Sopenharmony_ci} 628cb93a386Sopenharmony_ci 629cb93a386Sopenharmony_ciGrSurfaceProxyView TestHelper::CreateViewOnCpu(GrRecordingContext* rContext, 630cb93a386Sopenharmony_ci int wh, 631cb93a386Sopenharmony_ci Stats* stats) { 632cb93a386Sopenharmony_ci GrProxyProvider* proxyProvider = rContext->priv().proxyProvider(); 633cb93a386Sopenharmony_ci 634cb93a386Sopenharmony_ci sk_sp<GrTextureProxy> proxy = proxyProvider->createProxyFromBitmap(create_bitmap(wh), 635cb93a386Sopenharmony_ci GrMipmapped::kNo, 636cb93a386Sopenharmony_ci SkBackingFit::kExact, 637cb93a386Sopenharmony_ci SkBudgeted::kYes); 638cb93a386Sopenharmony_ci if (!proxy) { 639cb93a386Sopenharmony_ci return {}; 640cb93a386Sopenharmony_ci } 641cb93a386Sopenharmony_ci 642cb93a386Sopenharmony_ci GrSwizzle swizzle = rContext->priv().caps()->getReadSwizzle(proxy->backendFormat(), 643cb93a386Sopenharmony_ci GrColorType::kRGBA_8888); 644cb93a386Sopenharmony_ci ++stats->fNumSWCreations; 645cb93a386Sopenharmony_ci return {std::move(proxy), kImageOrigin, swizzle}; 646cb93a386Sopenharmony_ci} 647cb93a386Sopenharmony_ci 648cb93a386Sopenharmony_cibool TestHelper::FillInViewOnGpu(GrDirectContext* dContext, int wh, Stats* stats, 649cb93a386Sopenharmony_ci const GrSurfaceProxyView& lazyView, 650cb93a386Sopenharmony_ci sk_sp<GrThreadSafeCache::Trampoline> trampoline) { 651cb93a386Sopenharmony_ci 652cb93a386Sopenharmony_ci std::unique_ptr<skgpu::v1::SurfaceDrawContext> sdc = new_SDC(dContext, wh); 653cb93a386Sopenharmony_ci 654cb93a386Sopenharmony_ci GrPaint paint; 655cb93a386Sopenharmony_ci paint.setColor4f({0.0f, 0.0f, 1.0f, 1.0f}); 656cb93a386Sopenharmony_ci 657cb93a386Sopenharmony_ci sdc->clear(SkPMColor4f{1.0f, 1.0f, 1.0f, 1.0f}); 658cb93a386Sopenharmony_ci sdc->drawRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(), 659cb93a386Sopenharmony_ci { 10, 10, wh-10.0f, wh-10.0f }, &GrStyle::SimpleFill()); 660cb93a386Sopenharmony_ci 661cb93a386Sopenharmony_ci ++stats->fNumHWCreations; 662cb93a386Sopenharmony_ci auto view = sdc->readSurfaceView(); 663cb93a386Sopenharmony_ci 664cb93a386Sopenharmony_ci SkASSERT(view.swizzle() == lazyView.swizzle()); 665cb93a386Sopenharmony_ci SkASSERT(view.origin() == lazyView.origin()); 666cb93a386Sopenharmony_ci trampoline->fProxy = view.asTextureProxyRef(); 667cb93a386Sopenharmony_ci 668cb93a386Sopenharmony_ci return true; 669cb93a386Sopenharmony_ci} 670cb93a386Sopenharmony_ci 671cb93a386Sopenharmony_ciGrSurfaceProxyView TestHelper::AccessCachedView(GrRecordingContext* rContext, 672cb93a386Sopenharmony_ci GrThreadSafeCache* threadSafeCache, 673cb93a386Sopenharmony_ci int wh, 674cb93a386Sopenharmony_ci bool failLookup, bool failFillingIn, int id, 675cb93a386Sopenharmony_ci Stats* stats) { 676cb93a386Sopenharmony_ci GrUniqueKey key; 677cb93a386Sopenharmony_ci create_view_key(&key, wh, id); 678cb93a386Sopenharmony_ci 679cb93a386Sopenharmony_ci if (GrDirectContext* dContext = rContext->asDirectContext()) { 680cb93a386Sopenharmony_ci // The gpu thread gets priority over the recording threads. If the gpu thread is first, 681cb93a386Sopenharmony_ci // it crams a lazy proxy into the cache and then fills it in later. 682cb93a386Sopenharmony_ci auto [lazyView, trampoline] = GrThreadSafeCache::CreateLazyView( 683cb93a386Sopenharmony_ci dContext, GrColorType::kRGBA_8888, {wh, wh}, kImageOrigin, SkBackingFit::kExact); 684cb93a386Sopenharmony_ci ++stats->fNumLazyCreations; 685cb93a386Sopenharmony_ci 686cb93a386Sopenharmony_ci auto [view, data] = threadSafeCache->findOrAddWithData(key, lazyView); 687cb93a386Sopenharmony_ci if (view != lazyView) { 688cb93a386Sopenharmony_ci ++stats->fCacheHits; 689cb93a386Sopenharmony_ci return view; 690cb93a386Sopenharmony_ci } else if (id != kNoID) { 691cb93a386Sopenharmony_ci // Make sure, in this case, that the customData stuck 692cb93a386Sopenharmony_ci SkASSERT(data); 693cb93a386Sopenharmony_ci SkDEBUGCODE(const int* cachedID = static_cast<const int*>(data->data());) 694cb93a386Sopenharmony_ci SkASSERT(*cachedID == id); 695cb93a386Sopenharmony_ci } 696cb93a386Sopenharmony_ci 697cb93a386Sopenharmony_ci ++stats->fCacheMisses; 698cb93a386Sopenharmony_ci 699cb93a386Sopenharmony_ci if (failFillingIn) { 700cb93a386Sopenharmony_ci // Simulate something going horribly wrong at flush-time so no GrTexture is 701cb93a386Sopenharmony_ci // available to fulfill the lazy proxy. 702cb93a386Sopenharmony_ci return view; 703cb93a386Sopenharmony_ci } 704cb93a386Sopenharmony_ci 705cb93a386Sopenharmony_ci if (!FillInViewOnGpu(dContext, wh, stats, lazyView, std::move(trampoline))) { 706cb93a386Sopenharmony_ci // In this case something has gone disastrously wrong so set up to drop the draw 707cb93a386Sopenharmony_ci // that needed this resource and reduce future pollution of the cache. 708cb93a386Sopenharmony_ci threadSafeCache->remove(key); 709cb93a386Sopenharmony_ci return {}; 710cb93a386Sopenharmony_ci } 711cb93a386Sopenharmony_ci 712cb93a386Sopenharmony_ci return view; 713cb93a386Sopenharmony_ci } else { 714cb93a386Sopenharmony_ci GrSurfaceProxyView view; 715cb93a386Sopenharmony_ci 716cb93a386Sopenharmony_ci // We can "fail the lookup" to simulate a threaded race condition 717cb93a386Sopenharmony_ci if (view = threadSafeCache->find(key); !failLookup && view) { 718cb93a386Sopenharmony_ci ++stats->fCacheHits; 719cb93a386Sopenharmony_ci return view; 720cb93a386Sopenharmony_ci } 721cb93a386Sopenharmony_ci 722cb93a386Sopenharmony_ci ++stats->fCacheMisses; 723cb93a386Sopenharmony_ci 724cb93a386Sopenharmony_ci view = CreateViewOnCpu(rContext, wh, stats); 725cb93a386Sopenharmony_ci SkASSERT(view); 726cb93a386Sopenharmony_ci 727cb93a386Sopenharmony_ci auto [newView, data] = threadSafeCache->addWithData(key, view); 728cb93a386Sopenharmony_ci if (view == newView && id != kNoID) { 729cb93a386Sopenharmony_ci // Make sure, in this case, that the customData stuck 730cb93a386Sopenharmony_ci SkASSERT(data); 731cb93a386Sopenharmony_ci SkDEBUGCODE(const int* cachedID = static_cast<const int*>(data->data());) 732cb93a386Sopenharmony_ci SkASSERT(*cachedID == id); 733cb93a386Sopenharmony_ci } 734cb93a386Sopenharmony_ci return newView; 735cb93a386Sopenharmony_ci } 736cb93a386Sopenharmony_ci} 737cb93a386Sopenharmony_ci 738cb93a386Sopenharmony_ci// Case 1: ensure two DDL recorders share the view/vertexData 739cb93a386Sopenharmony_cistatic void test_1(GrDirectContext* dContext, skiatest::Reporter* reporter, 740cb93a386Sopenharmony_ci TestHelper::addAccessFP addAccess, 741cb93a386Sopenharmony_ci TestHelper::checkFP check) { 742cb93a386Sopenharmony_ci 743cb93a386Sopenharmony_ci TestHelper helper(dContext); 744cb93a386Sopenharmony_ci 745cb93a386Sopenharmony_ci (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, 1, false, false); 746cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH, 747cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, /*id*/ 1)); 748cb93a386Sopenharmony_ci 749cb93a386Sopenharmony_ci (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, 2, false, false); 750cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), kImageWH, 751cb93a386Sopenharmony_ci /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, /*id*/ 1)); 752cb93a386Sopenharmony_ci 753cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1); 754cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 0); 755cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 0); 756cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 1); 757cb93a386Sopenharmony_ci 758cb93a386Sopenharmony_ci helper.checkImage(reporter, helper.snap1()); 759cb93a386Sopenharmony_ci helper.checkImage(reporter, helper.snap2()); 760cb93a386Sopenharmony_ci} 761cb93a386Sopenharmony_ci 762cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache1View, reporter, ctxInfo) { 763cb93a386Sopenharmony_ci test_1(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView); 764cb93a386Sopenharmony_ci} 765cb93a386Sopenharmony_ci 766cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache1Verts, reporter, ctxInfo) { 767cb93a386Sopenharmony_ci test_1(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert); 768cb93a386Sopenharmony_ci} 769cb93a386Sopenharmony_ci 770cb93a386Sopenharmony_ci// Case 2: ensure that, if the direct context version wins, its result is reused by the 771cb93a386Sopenharmony_ci// DDL recorders 772cb93a386Sopenharmony_cistatic void test_2(GrDirectContext* dContext, skiatest::Reporter* reporter, 773cb93a386Sopenharmony_ci TestHelper::addAccessFP addAccess, 774cb93a386Sopenharmony_ci TestHelper::checkFP check) { 775cb93a386Sopenharmony_ci 776cb93a386Sopenharmony_ci TestHelper helper(dContext); 777cb93a386Sopenharmony_ci 778cb93a386Sopenharmony_ci (helper.*addAccess)(helper.liveCanvas(), kImageWH, 1, false, false); 779cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH, 780cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, /*id*/ 1)); 781cb93a386Sopenharmony_ci 782cb93a386Sopenharmony_ci (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, 2, false, false); 783cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH, 784cb93a386Sopenharmony_ci /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, /*id*/ 1)); 785cb93a386Sopenharmony_ci 786cb93a386Sopenharmony_ci (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, 3, false, false); 787cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), kImageWH, 788cb93a386Sopenharmony_ci /*hits*/ 2, /*misses*/ 1, /*refs*/ 3, /*id*/ 1)); 789cb93a386Sopenharmony_ci 790cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1); 791cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1); 792cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 1); 793cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0); 794cb93a386Sopenharmony_ci 795cb93a386Sopenharmony_ci helper.checkImage(reporter); 796cb93a386Sopenharmony_ci helper.checkImage(reporter, helper.snap1()); 797cb93a386Sopenharmony_ci helper.checkImage(reporter, helper.snap2()); 798cb93a386Sopenharmony_ci} 799cb93a386Sopenharmony_ci 800cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache2View, reporter, ctxInfo) { 801cb93a386Sopenharmony_ci test_2(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView); 802cb93a386Sopenharmony_ci} 803cb93a386Sopenharmony_ci 804cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache2Verts, reporter, ctxInfo) { 805cb93a386Sopenharmony_ci test_2(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert); 806cb93a386Sopenharmony_ci} 807cb93a386Sopenharmony_ci 808cb93a386Sopenharmony_ci// Case 3: ensure that, if the cpu-version wins, its result is reused by the direct context 809cb93a386Sopenharmony_cistatic void test_3(GrDirectContext* dContext, skiatest::Reporter* reporter, 810cb93a386Sopenharmony_ci TestHelper::addAccessFP addAccess, 811cb93a386Sopenharmony_ci TestHelper::checkFP check) { 812cb93a386Sopenharmony_ci 813cb93a386Sopenharmony_ci TestHelper helper(dContext); 814cb93a386Sopenharmony_ci 815cb93a386Sopenharmony_ci (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, 1, false, false); 816cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH, 817cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, /*id*/ 1)); 818cb93a386Sopenharmony_ci 819cb93a386Sopenharmony_ci (helper.*addAccess)(helper.liveCanvas(), kImageWH, 2, false, false); 820cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH, 821cb93a386Sopenharmony_ci /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, /*id*/ 1)); 822cb93a386Sopenharmony_ci 823cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1); 824cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1); 825cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 0); 826cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 1); 827cb93a386Sopenharmony_ci 828cb93a386Sopenharmony_ci helper.checkImage(reporter); 829cb93a386Sopenharmony_ci helper.checkImage(reporter, helper.snap1()); 830cb93a386Sopenharmony_ci} 831cb93a386Sopenharmony_ci 832cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache3View, reporter, ctxInfo) { 833cb93a386Sopenharmony_ci test_3(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView); 834cb93a386Sopenharmony_ci} 835cb93a386Sopenharmony_ci 836cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache3Verts, reporter, ctxInfo) { 837cb93a386Sopenharmony_ci test_3(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert); 838cb93a386Sopenharmony_ci} 839cb93a386Sopenharmony_ci 840cb93a386Sopenharmony_ci// Case 4: ensure that, if two DDL recorders get in a race, they still end up sharing a single 841cb93a386Sopenharmony_ci// view/vertexData 842cb93a386Sopenharmony_cistatic void test_4(GrDirectContext* dContext, skiatest::Reporter* reporter, 843cb93a386Sopenharmony_ci TestHelper::addAccessFP addAccess, 844cb93a386Sopenharmony_ci TestHelper::checkFP check) { 845cb93a386Sopenharmony_ci 846cb93a386Sopenharmony_ci TestHelper helper(dContext); 847cb93a386Sopenharmony_ci 848cb93a386Sopenharmony_ci (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, 1, false, false); 849cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH, 850cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, /*id*/ 1)); 851cb93a386Sopenharmony_ci 852cb93a386Sopenharmony_ci static const bool kFailLookup = true; 853cb93a386Sopenharmony_ci (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, 2, kFailLookup, false); 854cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), kImageWH, 855cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 2, /*refs*/ 2, /*id*/ 1)); 856cb93a386Sopenharmony_ci 857cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1); 858cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 0); 859cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 0); 860cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 2); 861cb93a386Sopenharmony_ci 862cb93a386Sopenharmony_ci helper.checkImage(reporter, helper.snap1()); 863cb93a386Sopenharmony_ci helper.checkImage(reporter, helper.snap2()); 864cb93a386Sopenharmony_ci} 865cb93a386Sopenharmony_ci 866cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache4View, reporter, ctxInfo) { 867cb93a386Sopenharmony_ci test_4(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView); 868cb93a386Sopenharmony_ci} 869cb93a386Sopenharmony_ci 870cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache4Verts, reporter, ctxInfo) { 871cb93a386Sopenharmony_ci test_4(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert); 872cb93a386Sopenharmony_ci} 873cb93a386Sopenharmony_ci 874cb93a386Sopenharmony_ci// Case 4.5: check that, if a live rendering and a DDL recording get into a race, the live 875cb93a386Sopenharmony_ci// rendering takes precedence. 876cb93a386Sopenharmony_cistatic void test_4_5(GrDirectContext* dContext, skiatest::Reporter* reporter, 877cb93a386Sopenharmony_ci TestHelper::addAccessFP addAccess, 878cb93a386Sopenharmony_ci TestHelper::checkFP check) { 879cb93a386Sopenharmony_ci 880cb93a386Sopenharmony_ci TestHelper helper(dContext); 881cb93a386Sopenharmony_ci 882cb93a386Sopenharmony_ci (helper.*addAccess)(helper.liveCanvas(), kImageWH, 1, false, false); 883cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH, 884cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, /*id*/ 1)); 885cb93a386Sopenharmony_ci 886cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1); 887cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1); 888cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 1); 889cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0); 890cb93a386Sopenharmony_ci 891cb93a386Sopenharmony_ci static const bool kFailLookup = true; 892cb93a386Sopenharmony_ci (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, 2, kFailLookup, false); 893cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH, 894cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 2, /*refs*/ 2, /*id*/ 1)); 895cb93a386Sopenharmony_ci 896cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1); 897cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1); 898cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 1); 899cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 1); 900cb93a386Sopenharmony_ci 901cb93a386Sopenharmony_ci helper.checkImage(reporter); 902cb93a386Sopenharmony_ci helper.checkImage(reporter, helper.snap1()); 903cb93a386Sopenharmony_ci} 904cb93a386Sopenharmony_ci 905cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache4_5View, reporter, ctxInfo) { 906cb93a386Sopenharmony_ci test_4_5(ctxInfo.directContext(), reporter, 907cb93a386Sopenharmony_ci &TestHelper::addViewAccess, &TestHelper::checkView); 908cb93a386Sopenharmony_ci} 909cb93a386Sopenharmony_ci 910cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache4_5Verts, reporter, ctxInfo) { 911cb93a386Sopenharmony_ci test_4_5(ctxInfo.directContext(), reporter, 912cb93a386Sopenharmony_ci &TestHelper::addVertAccess, &TestHelper::checkVert); 913cb93a386Sopenharmony_ci} 914cb93a386Sopenharmony_ci 915cb93a386Sopenharmony_ci// Case 4.75: check that, if a live rendering fails to generate the content needed to instantiate 916cb93a386Sopenharmony_ci// its lazy proxy, life goes on 917cb93a386Sopenharmony_cistatic void test_4_75(GrDirectContext* dContext, skiatest::Reporter* reporter, 918cb93a386Sopenharmony_ci TestHelper::addAccessFP addAccess, 919cb93a386Sopenharmony_ci TestHelper::checkFP check) { 920cb93a386Sopenharmony_ci 921cb93a386Sopenharmony_ci TestHelper helper(dContext); 922cb93a386Sopenharmony_ci 923cb93a386Sopenharmony_ci static const bool kFailFillingIn = true; 924cb93a386Sopenharmony_ci (helper.*addAccess)(helper.liveCanvas(), kImageWH, kNoID, false, kFailFillingIn); 925cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH, 926cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID)); 927cb93a386Sopenharmony_ci 928cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1); 929cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1); 930cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 0); 931cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0); 932cb93a386Sopenharmony_ci 933cb93a386Sopenharmony_ci dContext->flush(); 934cb93a386Sopenharmony_ci dContext->submit(true); 935cb93a386Sopenharmony_ci 936cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH, 937cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 1, /*refs*/ 0, kNoID)); 938cb93a386Sopenharmony_ci 939cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1); 940cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1); 941cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 0); 942cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0); 943cb93a386Sopenharmony_ci} 944cb93a386Sopenharmony_ci 945cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache4_75View, reporter, ctxInfo) { 946cb93a386Sopenharmony_ci test_4_75(ctxInfo.directContext(), reporter, 947cb93a386Sopenharmony_ci &TestHelper::addViewAccess, &TestHelper::checkView); 948cb93a386Sopenharmony_ci} 949cb93a386Sopenharmony_ci 950cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache4_75Verts, reporter, ctxInfo) { 951cb93a386Sopenharmony_ci test_4_75(ctxInfo.directContext(), reporter, 952cb93a386Sopenharmony_ci &TestHelper::addVertAccess, &TestHelper::checkVert); 953cb93a386Sopenharmony_ci} 954cb93a386Sopenharmony_ci 955cb93a386Sopenharmony_ci// Case 5: ensure that expanding the map works (esp. wrt custom data) 956cb93a386Sopenharmony_cistatic void test_5(GrDirectContext* dContext, skiatest::Reporter* reporter, 957cb93a386Sopenharmony_ci TestHelper::addAccessFP addAccess, 958cb93a386Sopenharmony_ci TestHelper::checkFP check) { 959cb93a386Sopenharmony_ci 960cb93a386Sopenharmony_ci TestHelper helper(dContext); 961cb93a386Sopenharmony_ci 962cb93a386Sopenharmony_ci auto threadSafeCache = helper.threadSafeCache(); 963cb93a386Sopenharmony_ci 964cb93a386Sopenharmony_ci int size = 16; 965cb93a386Sopenharmony_ci (helper.*addAccess)(helper.ddlCanvas1(), size, /*id*/ size, false, false); 966cb93a386Sopenharmony_ci 967cb93a386Sopenharmony_ci size_t initialSize = threadSafeCache->approxBytesUsedForHash(); 968cb93a386Sopenharmony_ci 969cb93a386Sopenharmony_ci while (initialSize == threadSafeCache->approxBytesUsedForHash()) { 970cb93a386Sopenharmony_ci size *= 2; 971cb93a386Sopenharmony_ci (helper.*addAccess)(helper.ddlCanvas1(), size, /*id*/ size, false, false); 972cb93a386Sopenharmony_ci } 973cb93a386Sopenharmony_ci 974cb93a386Sopenharmony_ci for (int i = 16; i <= size; i *= 2) { 975cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), 976cb93a386Sopenharmony_ci /*wh*/ i, 977cb93a386Sopenharmony_ci /*hits*/ 0, 978cb93a386Sopenharmony_ci /*misses*/ threadSafeCache->numEntries(), 979cb93a386Sopenharmony_ci /*refs*/ 1, 980cb93a386Sopenharmony_ci /*id*/ i)); 981cb93a386Sopenharmony_ci } 982cb93a386Sopenharmony_ci} 983cb93a386Sopenharmony_ci 984cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache5View, reporter, ctxInfo) { 985cb93a386Sopenharmony_ci test_5(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView); 986cb93a386Sopenharmony_ci} 987cb93a386Sopenharmony_ci 988cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache5Verts, reporter, ctxInfo) { 989cb93a386Sopenharmony_ci test_5(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert); 990cb93a386Sopenharmony_ci} 991cb93a386Sopenharmony_ci 992cb93a386Sopenharmony_ci// Case 6: Check on dropping refs. In particular, that the cache has its own ref to keep 993cb93a386Sopenharmony_ci// the backing resource alive and locked. 994cb93a386Sopenharmony_cistatic void test_6(GrDirectContext* dContext, skiatest::Reporter* reporter, 995cb93a386Sopenharmony_ci TestHelper::addAccessFP addAccess, 996cb93a386Sopenharmony_ci TestHelper::checkFP check) { 997cb93a386Sopenharmony_ci 998cb93a386Sopenharmony_ci TestHelper helper(dContext); 999cb93a386Sopenharmony_ci 1000cb93a386Sopenharmony_ci (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false); 1001cb93a386Sopenharmony_ci sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1(); 1002cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(nullptr, kImageWH, 1003cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID)); 1004cb93a386Sopenharmony_ci 1005cb93a386Sopenharmony_ci (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, kNoID, false, false); 1006cb93a386Sopenharmony_ci sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2(); 1007cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(nullptr, kImageWH, 1008cb93a386Sopenharmony_ci /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, kNoID)); 1009cb93a386Sopenharmony_ci 1010cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1); 1011cb93a386Sopenharmony_ci 1012cb93a386Sopenharmony_ci ddl1 = nullptr; 1013cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(nullptr, kImageWH, 1014cb93a386Sopenharmony_ci /*hits*/ 1, /*misses*/ 1, /*refs*/ 1, kNoID)); 1015cb93a386Sopenharmony_ci 1016cb93a386Sopenharmony_ci ddl2 = nullptr; 1017cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(nullptr, kImageWH, 1018cb93a386Sopenharmony_ci /*hits*/ 1, /*misses*/ 1, /*refs*/ 0, kNoID)); 1019cb93a386Sopenharmony_ci 1020cb93a386Sopenharmony_ci // The cache still has its ref 1021cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1); 1022cb93a386Sopenharmony_ci 1023cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(nullptr, kImageWH, 1024cb93a386Sopenharmony_ci /*hits*/ 1, /*misses*/ 1, /*refs*/ 0, kNoID)); 1025cb93a386Sopenharmony_ci} 1026cb93a386Sopenharmony_ci 1027cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache6View, reporter, ctxInfo) { 1028cb93a386Sopenharmony_ci test_6(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView); 1029cb93a386Sopenharmony_ci} 1030cb93a386Sopenharmony_ci 1031cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache6Verts, reporter, ctxInfo) { 1032cb93a386Sopenharmony_ci test_6(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert); 1033cb93a386Sopenharmony_ci} 1034cb93a386Sopenharmony_ci 1035cb93a386Sopenharmony_ci// Case 7: Check that invoking dropAllRefs and dropUniqueRefs directly works as expected; i.e., 1036cb93a386Sopenharmony_ci// dropAllRefs removes everything while dropUniqueRefs is more measured. 1037cb93a386Sopenharmony_cistatic void test_7(GrDirectContext* dContext, skiatest::Reporter* reporter, 1038cb93a386Sopenharmony_ci TestHelper::addAccessFP addAccess, 1039cb93a386Sopenharmony_ci TestHelper::checkFP check) { 1040cb93a386Sopenharmony_ci 1041cb93a386Sopenharmony_ci TestHelper helper(dContext); 1042cb93a386Sopenharmony_ci 1043cb93a386Sopenharmony_ci (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false); 1044cb93a386Sopenharmony_ci sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1(); 1045cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(nullptr, kImageWH, 1046cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID)); 1047cb93a386Sopenharmony_ci 1048cb93a386Sopenharmony_ci (helper.*addAccess)(helper.ddlCanvas2(), 2*kImageWH, kNoID, false, false); 1049cb93a386Sopenharmony_ci sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2(); 1050cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(nullptr, 2*kImageWH, 1051cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 2, /*refs*/ 1, kNoID)); 1052cb93a386Sopenharmony_ci 1053cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2); 1054cb93a386Sopenharmony_ci 1055cb93a386Sopenharmony_ci helper.threadSafeCache()->dropUniqueRefs(nullptr); 1056cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2); 1057cb93a386Sopenharmony_ci 1058cb93a386Sopenharmony_ci ddl1 = nullptr; 1059cb93a386Sopenharmony_ci 1060cb93a386Sopenharmony_ci helper.threadSafeCache()->dropUniqueRefs(nullptr); 1061cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1); 1062cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(nullptr, 2*kImageWH, 1063cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 2, /*refs*/ 1, kNoID)); 1064cb93a386Sopenharmony_ci 1065cb93a386Sopenharmony_ci helper.threadSafeCache()->dropAllRefs(); 1066cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0); 1067cb93a386Sopenharmony_ci 1068cb93a386Sopenharmony_ci ddl2 = nullptr; 1069cb93a386Sopenharmony_ci} 1070cb93a386Sopenharmony_ci 1071cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache7View, reporter, ctxInfo) { 1072cb93a386Sopenharmony_ci test_7(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView); 1073cb93a386Sopenharmony_ci} 1074cb93a386Sopenharmony_ci 1075cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache7Verts, reporter, ctxInfo) { 1076cb93a386Sopenharmony_ci test_7(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert); 1077cb93a386Sopenharmony_ci} 1078cb93a386Sopenharmony_ci 1079cb93a386Sopenharmony_ci// Case 8: This checks that GrContext::abandonContext works as expected wrt the thread 1080cb93a386Sopenharmony_ci// safe cache. This simulates the case where we have one DDL that has finished 1081cb93a386Sopenharmony_ci// recording but one still recording when the abandonContext fires. 1082cb93a386Sopenharmony_cistatic void test_8(GrDirectContext* dContext, skiatest::Reporter* reporter, 1083cb93a386Sopenharmony_ci TestHelper::addAccessFP addAccess, 1084cb93a386Sopenharmony_ci TestHelper::checkFP check) { 1085cb93a386Sopenharmony_ci 1086cb93a386Sopenharmony_ci TestHelper helper(dContext); 1087cb93a386Sopenharmony_ci 1088cb93a386Sopenharmony_ci (helper.*addAccess)(helper.liveCanvas(), kImageWH, kNoID, false, false); 1089cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH, 1090cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID)); 1091cb93a386Sopenharmony_ci 1092cb93a386Sopenharmony_ci (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false); 1093cb93a386Sopenharmony_ci sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1(); 1094cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH, 1095cb93a386Sopenharmony_ci /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, kNoID)); 1096cb93a386Sopenharmony_ci 1097cb93a386Sopenharmony_ci (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, kNoID, false, false); 1098cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), kImageWH, 1099cb93a386Sopenharmony_ci /*hits*/ 2, /*misses*/ 1, /*refs*/ 3, kNoID)); 1100cb93a386Sopenharmony_ci 1101cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1); 1102cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1); 1103cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 1); 1104cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0); 1105cb93a386Sopenharmony_ci 1106cb93a386Sopenharmony_ci dContext->abandonContext(); // This should exercise dropAllRefs 1107cb93a386Sopenharmony_ci 1108cb93a386Sopenharmony_ci sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2(); 1109cb93a386Sopenharmony_ci 1110cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0); 1111cb93a386Sopenharmony_ci 1112cb93a386Sopenharmony_ci ddl1 = nullptr; 1113cb93a386Sopenharmony_ci ddl2 = nullptr; 1114cb93a386Sopenharmony_ci} 1115cb93a386Sopenharmony_ci 1116cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache8View, reporter, ctxInfo) { 1117cb93a386Sopenharmony_ci test_8(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView); 1118cb93a386Sopenharmony_ci} 1119cb93a386Sopenharmony_ci 1120cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache8Verts, reporter, ctxInfo) { 1121cb93a386Sopenharmony_ci test_8(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert); 1122cb93a386Sopenharmony_ci} 1123cb93a386Sopenharmony_ci 1124cb93a386Sopenharmony_ci// Case 9: This checks that GrContext::releaseResourcesAndAbandonContext works as expected wrt 1125cb93a386Sopenharmony_ci// the thread safe cache. This simulates the case where we have one DDL that has finished 1126cb93a386Sopenharmony_ci// recording but one still recording when the releaseResourcesAndAbandonContext fires. 1127cb93a386Sopenharmony_cistatic void test_9(GrDirectContext* dContext, skiatest::Reporter* reporter, 1128cb93a386Sopenharmony_ci TestHelper::addAccessFP addAccess, 1129cb93a386Sopenharmony_ci TestHelper::checkFP check) { 1130cb93a386Sopenharmony_ci 1131cb93a386Sopenharmony_ci TestHelper helper(dContext); 1132cb93a386Sopenharmony_ci 1133cb93a386Sopenharmony_ci (helper.*addAccess)(helper.liveCanvas(), kImageWH, kNoID, false, false); 1134cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH, 1135cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID)); 1136cb93a386Sopenharmony_ci 1137cb93a386Sopenharmony_ci (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false); 1138cb93a386Sopenharmony_ci sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1(); 1139cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH, 1140cb93a386Sopenharmony_ci /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, kNoID)); 1141cb93a386Sopenharmony_ci 1142cb93a386Sopenharmony_ci (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, kNoID, false, false); 1143cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), kImageWH, 1144cb93a386Sopenharmony_ci /*hits*/ 2, /*misses*/ 1, /*refs*/ 3, kNoID)); 1145cb93a386Sopenharmony_ci 1146cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1); 1147cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumLazyCreations == 1); 1148cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumHWCreations == 1); 1149cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.stats()->fNumSWCreations == 0); 1150cb93a386Sopenharmony_ci 1151cb93a386Sopenharmony_ci dContext->releaseResourcesAndAbandonContext(); // This should hit dropAllRefs 1152cb93a386Sopenharmony_ci 1153cb93a386Sopenharmony_ci sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2(); 1154cb93a386Sopenharmony_ci 1155cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0); 1156cb93a386Sopenharmony_ci 1157cb93a386Sopenharmony_ci ddl1 = nullptr; 1158cb93a386Sopenharmony_ci ddl2 = nullptr; 1159cb93a386Sopenharmony_ci} 1160cb93a386Sopenharmony_ci 1161cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache9View, reporter, ctxInfo) { 1162cb93a386Sopenharmony_ci test_9(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView); 1163cb93a386Sopenharmony_ci} 1164cb93a386Sopenharmony_ci 1165cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache9Verts, reporter, ctxInfo) { 1166cb93a386Sopenharmony_ci test_9(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert); 1167cb93a386Sopenharmony_ci} 1168cb93a386Sopenharmony_ci 1169cb93a386Sopenharmony_ci// Case 10: This checks that the GrContext::purgeUnlockedResources(size_t) variant works as 1170cb93a386Sopenharmony_ci// expected wrt the thread safe cache. It, in particular, tests out the MRU behavior 1171cb93a386Sopenharmony_ci// of the shared cache. 1172cb93a386Sopenharmony_cistatic void test_10(GrDirectContext* dContext, skiatest::Reporter* reporter, 1173cb93a386Sopenharmony_ci TestHelper::addAccessFP addAccess, 1174cb93a386Sopenharmony_ci TestHelper::checkFP check) { 1175cb93a386Sopenharmony_ci 1176cb93a386Sopenharmony_ci if (GrBackendApi::kOpenGL != dContext->backend()) { 1177cb93a386Sopenharmony_ci // The lower-level backends have too much going on for the following simple purging 1178cb93a386Sopenharmony_ci // test to work 1179cb93a386Sopenharmony_ci return; 1180cb93a386Sopenharmony_ci } 1181cb93a386Sopenharmony_ci 1182cb93a386Sopenharmony_ci TestHelper helper(dContext); 1183cb93a386Sopenharmony_ci 1184cb93a386Sopenharmony_ci (helper.*addAccess)(helper.liveCanvas(), kImageWH, kNoID, false, false); 1185cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH, 1186cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID)); 1187cb93a386Sopenharmony_ci 1188cb93a386Sopenharmony_ci (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false); 1189cb93a386Sopenharmony_ci sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1(); 1190cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH, 1191cb93a386Sopenharmony_ci /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, kNoID)); 1192cb93a386Sopenharmony_ci 1193cb93a386Sopenharmony_ci (helper.*addAccess)(helper.liveCanvas(), 2*kImageWH, kNoID, false, false); 1194cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH, 1195cb93a386Sopenharmony_ci /*hits*/ 1, /*misses*/ 2, /*refs*/ 1, kNoID)); 1196cb93a386Sopenharmony_ci 1197cb93a386Sopenharmony_ci (helper.*addAccess)(helper.ddlCanvas2(), 2*kImageWH, kNoID, false, false); 1198cb93a386Sopenharmony_ci sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2(); 1199cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), 2*kImageWH, 1200cb93a386Sopenharmony_ci /*hits*/ 2, /*misses*/ 2, /*refs*/ 2, kNoID)); 1201cb93a386Sopenharmony_ci 1202cb93a386Sopenharmony_ci dContext->flush(); 1203cb93a386Sopenharmony_ci dContext->submit(true); 1204cb93a386Sopenharmony_ci 1205cb93a386Sopenharmony_ci // This should clear out everything but the textures locked in the thread-safe cache 1206cb93a386Sopenharmony_ci dContext->purgeUnlockedResources(false); 1207cb93a386Sopenharmony_ci 1208cb93a386Sopenharmony_ci ddl1 = nullptr; 1209cb93a386Sopenharmony_ci ddl2 = nullptr; 1210cb93a386Sopenharmony_ci 1211cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2); 1212cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH, 1213cb93a386Sopenharmony_ci /*hits*/ 2, /*misses*/ 2, /*refs*/ 0, kNoID)); 1214cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH, 1215cb93a386Sopenharmony_ci /*hits*/ 2, /*misses*/ 2, /*refs*/ 0, kNoID)); 1216cb93a386Sopenharmony_ci 1217cb93a386Sopenharmony_ci // Regardless of which image is MRU, this should force the other out 1218cb93a386Sopenharmony_ci size_t desiredBytes = helper.gpuSize(2*kImageWH) + helper.gpuSize(kImageWH)/2; 1219cb93a386Sopenharmony_ci 1220cb93a386Sopenharmony_ci auto cache = dContext->priv().getResourceCache(); 1221cb93a386Sopenharmony_ci size_t currentBytes = cache->getResourceBytes(); 1222cb93a386Sopenharmony_ci 1223cb93a386Sopenharmony_ci SkASSERT(currentBytes >= desiredBytes); 1224cb93a386Sopenharmony_ci size_t amountToPurge = currentBytes - desiredBytes; 1225cb93a386Sopenharmony_ci 1226cb93a386Sopenharmony_ci // The 2*kImageWH texture should be MRU. 1227cb93a386Sopenharmony_ci dContext->purgeUnlockedResources(amountToPurge, true); 1228cb93a386Sopenharmony_ci 1229cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1); 1230cb93a386Sopenharmony_ci 1231cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH, 1232cb93a386Sopenharmony_ci /*hits*/ 2, /*misses*/ 2, /*refs*/ 0, kNoID)); 1233cb93a386Sopenharmony_ci} 1234cb93a386Sopenharmony_ci 1235cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache10View, reporter, ctxInfo) { 1236cb93a386Sopenharmony_ci test_10(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView); 1237cb93a386Sopenharmony_ci} 1238cb93a386Sopenharmony_ci 1239cb93a386Sopenharmony_ci// To enable test_10 with verts would require a bit more work, namely: 1240cb93a386Sopenharmony_ci// have a different # of verts based on size 1241cb93a386Sopenharmony_ci// also pass in a gpuSize function to 'test_10' 1242cb93a386Sopenharmony_ci//DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache10Verts, reporter, ctxInfo) { 1243cb93a386Sopenharmony_ci// test_10(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert); 1244cb93a386Sopenharmony_ci//} 1245cb93a386Sopenharmony_ci 1246cb93a386Sopenharmony_ci// Case 11: This checks that scratch-only variant of GrContext::purgeUnlockedResources works as 1247cb93a386Sopenharmony_ci// expected wrt the thread safe cache. In particular, that when 'scratchResourcesOnly' 1248cb93a386Sopenharmony_ci// is true, the call has no effect on the cache. 1249cb93a386Sopenharmony_cistatic void test_11(GrDirectContext* dContext, skiatest::Reporter* reporter, 1250cb93a386Sopenharmony_ci TestHelper::addAccessFP addAccess, 1251cb93a386Sopenharmony_ci TestHelper::checkFP check) { 1252cb93a386Sopenharmony_ci 1253cb93a386Sopenharmony_ci TestHelper helper(dContext); 1254cb93a386Sopenharmony_ci 1255cb93a386Sopenharmony_ci (helper.*addAccess)(helper.liveCanvas(), kImageWH, kNoID, false, false); 1256cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH, 1257cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID)); 1258cb93a386Sopenharmony_ci 1259cb93a386Sopenharmony_ci (helper.*addAccess)(helper.liveCanvas(), 2*kImageWH, kNoID, false, false); 1260cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH, 1261cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 2, /*refs*/ 1, kNoID)); 1262cb93a386Sopenharmony_ci 1263cb93a386Sopenharmony_ci dContext->flush(); 1264cb93a386Sopenharmony_ci dContext->submit(true); 1265cb93a386Sopenharmony_ci 1266cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2); 1267cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH, 1268cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 2, /*refs*/ 0, kNoID)); 1269cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH, 1270cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 2, /*refs*/ 0, kNoID)); 1271cb93a386Sopenharmony_ci 1272cb93a386Sopenharmony_ci // This shouldn't remove anything from the cache 1273cb93a386Sopenharmony_ci dContext->purgeUnlockedResources(/* scratchResourcesOnly */ true); 1274cb93a386Sopenharmony_ci 1275cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2); 1276cb93a386Sopenharmony_ci 1277cb93a386Sopenharmony_ci dContext->purgeUnlockedResources(/* scratchResourcesOnly */ false); 1278cb93a386Sopenharmony_ci 1279cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0); 1280cb93a386Sopenharmony_ci} 1281cb93a386Sopenharmony_ci 1282cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache11View, reporter, ctxInfo) { 1283cb93a386Sopenharmony_ci test_11(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView); 1284cb93a386Sopenharmony_ci} 1285cb93a386Sopenharmony_ci 1286cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache11Verts, reporter, ctxInfo) { 1287cb93a386Sopenharmony_ci test_11(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert); 1288cb93a386Sopenharmony_ci} 1289cb93a386Sopenharmony_ci 1290cb93a386Sopenharmony_ci// Case 12: Test out purges caused by resetting the cache budget to 0. Note that, due to 1291cb93a386Sopenharmony_ci// the how the cache operates (i.e., not directly driven by ref/unrefs) there 1292cb93a386Sopenharmony_ci// needs to be an explicit kick to purge the cache. 1293cb93a386Sopenharmony_cistatic void test_12(GrDirectContext* dContext, skiatest::Reporter* reporter, 1294cb93a386Sopenharmony_ci TestHelper::addAccessFP addAccess, 1295cb93a386Sopenharmony_ci TestHelper::checkFP check) { 1296cb93a386Sopenharmony_ci 1297cb93a386Sopenharmony_ci TestHelper helper(dContext); 1298cb93a386Sopenharmony_ci 1299cb93a386Sopenharmony_ci (helper.*addAccess)(helper.liveCanvas(), kImageWH, kNoID, false, false); 1300cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH, 1301cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID)); 1302cb93a386Sopenharmony_ci (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false); 1303cb93a386Sopenharmony_ci sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1(); 1304cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH, 1305cb93a386Sopenharmony_ci /*hits*/ 1, /*misses*/ 1, /*refs*/ 2, kNoID)); 1306cb93a386Sopenharmony_ci 1307cb93a386Sopenharmony_ci (helper.*addAccess)(helper.liveCanvas(), 2*kImageWH, kNoID, false, false); 1308cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH, 1309cb93a386Sopenharmony_ci /*hits*/ 1, /*misses*/ 2, /*refs*/ 1, kNoID)); 1310cb93a386Sopenharmony_ci 1311cb93a386Sopenharmony_ci dContext->flush(); 1312cb93a386Sopenharmony_ci dContext->submit(true); 1313cb93a386Sopenharmony_ci 1314cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2); 1315cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), kImageWH, 1316cb93a386Sopenharmony_ci /*hits*/ 1, /*misses*/ 2, /*refs*/ 1, kNoID)); 1317cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH, 1318cb93a386Sopenharmony_ci /*hits*/ 1, /*misses*/ 2, /*refs*/ 0, kNoID)); 1319cb93a386Sopenharmony_ci 1320cb93a386Sopenharmony_ci dContext->setResourceCacheLimit(0); 1321cb93a386Sopenharmony_ci 1322cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1); 1323cb93a386Sopenharmony_ci 1324cb93a386Sopenharmony_ci ddl1 = nullptr; 1325cb93a386Sopenharmony_ci 1326cb93a386Sopenharmony_ci // Explicitly kick off the purge - it won't happen automatically on unref 1327cb93a386Sopenharmony_ci dContext->performDeferredCleanup(std::chrono::milliseconds(0)); 1328cb93a386Sopenharmony_ci 1329cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0); 1330cb93a386Sopenharmony_ci} 1331cb93a386Sopenharmony_ci 1332cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache12View, reporter, ctxInfo) { 1333cb93a386Sopenharmony_ci test_12(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView); 1334cb93a386Sopenharmony_ci} 1335cb93a386Sopenharmony_ci 1336cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache12Verts, reporter, ctxInfo) { 1337cb93a386Sopenharmony_ci test_12(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert); 1338cb93a386Sopenharmony_ci} 1339cb93a386Sopenharmony_ci 1340cb93a386Sopenharmony_ci// Case 13: Test out the 'msNotUsed' parameter to GrContext::performDeferredCleanup. 1341cb93a386Sopenharmony_cistatic void test_13(GrDirectContext* dContext, skiatest::Reporter* reporter, 1342cb93a386Sopenharmony_ci TestHelper::addAccessFP addAccess, 1343cb93a386Sopenharmony_ci TestHelper::checkFP check) { 1344cb93a386Sopenharmony_ci 1345cb93a386Sopenharmony_ci TestHelper helper(dContext); 1346cb93a386Sopenharmony_ci 1347cb93a386Sopenharmony_ci (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false); 1348cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH, 1349cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID)); 1350cb93a386Sopenharmony_ci sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1(); 1351cb93a386Sopenharmony_ci 1352cb93a386Sopenharmony_ci std::this_thread::sleep_for(std::chrono::milliseconds(5)); 1353cb93a386Sopenharmony_ci auto firstTime = GrStdSteadyClock::now(); 1354cb93a386Sopenharmony_ci std::this_thread::sleep_for(std::chrono::milliseconds(5)); 1355cb93a386Sopenharmony_ci 1356cb93a386Sopenharmony_ci (helper.*addAccess)(helper.ddlCanvas2(), 2*kImageWH, kNoID, false, false); 1357cb93a386Sopenharmony_ci 1358cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), 2*kImageWH, 1359cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 2, /*refs*/ 1, kNoID)); 1360cb93a386Sopenharmony_ci sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2(); 1361cb93a386Sopenharmony_ci 1362cb93a386Sopenharmony_ci ddl1 = nullptr; 1363cb93a386Sopenharmony_ci ddl2 = nullptr; 1364cb93a386Sopenharmony_ci 1365cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 2); 1366cb93a386Sopenharmony_ci 1367cb93a386Sopenharmony_ci auto secondTime = GrStdSteadyClock::now(); 1368cb93a386Sopenharmony_ci 1369cb93a386Sopenharmony_ci auto msecs = std::chrono::duration_cast<std::chrono::milliseconds>(secondTime - firstTime); 1370cb93a386Sopenharmony_ci dContext->performDeferredCleanup(msecs); 1371cb93a386Sopenharmony_ci 1372cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1); 1373cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.liveCanvas(), 2*kImageWH, 1374cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 2, /*refs*/ 0, kNoID)); 1375cb93a386Sopenharmony_ci} 1376cb93a386Sopenharmony_ci 1377cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache13View, reporter, ctxInfo) { 1378cb93a386Sopenharmony_ci test_13(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView); 1379cb93a386Sopenharmony_ci} 1380cb93a386Sopenharmony_ci 1381cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache13Verts, reporter, ctxInfo) { 1382cb93a386Sopenharmony_ci test_13(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert); 1383cb93a386Sopenharmony_ci} 1384cb93a386Sopenharmony_ci 1385cb93a386Sopenharmony_ci// Case 14: Test out mixing & matching view & vertex data w/ recycling of the cache entries to 1386cb93a386Sopenharmony_ci// wring out the anonymous union code. This is mainly for the MSAN bot's consumption. 1387cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache14, reporter, ctxInfo) { 1388cb93a386Sopenharmony_ci constexpr int kBestPrimeNumber = 73; // palindromic in binary 1389cb93a386Sopenharmony_ci SkRandom rand(kBestPrimeNumber); 1390cb93a386Sopenharmony_ci 1391cb93a386Sopenharmony_ci TestHelper helper(ctxInfo.directContext()); 1392cb93a386Sopenharmony_ci 1393cb93a386Sopenharmony_ci for (int i = 0; i < 2; ++i) { 1394cb93a386Sopenharmony_ci SkCanvas* ddlCanvas = (!i) ? helper.ddlCanvas1() : helper.ddlCanvas2(); 1395cb93a386Sopenharmony_ci 1396cb93a386Sopenharmony_ci for (int j = 0; j < 10; ++j) { 1397cb93a386Sopenharmony_ci int numResources = 10*i + j + 1; 1398cb93a386Sopenharmony_ci int wh = numResources; 1399cb93a386Sopenharmony_ci 1400cb93a386Sopenharmony_ci if (rand.nextBool()) { 1401cb93a386Sopenharmony_ci helper.addViewAccess(ddlCanvas, wh, kNoID, false, false); 1402cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.checkView(ddlCanvas, wh, 1403cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ numResources, 1404cb93a386Sopenharmony_ci /*refs*/ 1, kNoID)); 1405cb93a386Sopenharmony_ci } else { 1406cb93a386Sopenharmony_ci helper.addVertAccess(ddlCanvas, wh, kNoID, false, false); 1407cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.checkVert(ddlCanvas, wh, 1408cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ numResources, 1409cb93a386Sopenharmony_ci /*refs*/ 1, kNoID)); 1410cb93a386Sopenharmony_ci } 1411cb93a386Sopenharmony_ci } 1412cb93a386Sopenharmony_ci 1413cb93a386Sopenharmony_ci if (!i) { 1414cb93a386Sopenharmony_ci // Drop all the accumulated resources from the thread-safe cache 1415cb93a386Sopenharmony_ci helper.snap1(); 1416cb93a386Sopenharmony_ci ctxInfo.directContext()->purgeUnlockedResources(/* scratchResourcesOnly */ false); 1417cb93a386Sopenharmony_ci } 1418cb93a386Sopenharmony_ci } 1419cb93a386Sopenharmony_ci} 1420cb93a386Sopenharmony_ci 1421cb93a386Sopenharmony_ci// Case 15: Test out posting invalidation messages that involve the thread safe cache 1422cb93a386Sopenharmony_cistatic void test_15(GrDirectContext* dContext, skiatest::Reporter* reporter, 1423cb93a386Sopenharmony_ci TestHelper::addAccessFP addAccess, 1424cb93a386Sopenharmony_ci TestHelper::checkFP check, 1425cb93a386Sopenharmony_ci void (*create_key)(GrUniqueKey*, int wh, int id)) { 1426cb93a386Sopenharmony_ci 1427cb93a386Sopenharmony_ci TestHelper helper(dContext); 1428cb93a386Sopenharmony_ci 1429cb93a386Sopenharmony_ci (helper.*addAccess)(helper.ddlCanvas1(), kImageWH, kNoID, false, false); 1430cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas1(), kImageWH, 1431cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID)); 1432cb93a386Sopenharmony_ci sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1(); 1433cb93a386Sopenharmony_ci 1434cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1); 1435cb93a386Sopenharmony_ci 1436cb93a386Sopenharmony_ci GrUniqueKey key; 1437cb93a386Sopenharmony_ci (*create_key)(&key, kImageWH, kNoID); 1438cb93a386Sopenharmony_ci 1439cb93a386Sopenharmony_ci GrUniqueKeyInvalidatedMessage msg(key, dContext->priv().contextID(), 1440cb93a386Sopenharmony_ci /* inThreadSafeCache */ true); 1441cb93a386Sopenharmony_ci 1442cb93a386Sopenharmony_ci SkMessageBus<GrUniqueKeyInvalidatedMessage, uint32_t>::Post(msg); 1443cb93a386Sopenharmony_ci 1444cb93a386Sopenharmony_ci // This purge call is needed to process the invalidation messages 1445cb93a386Sopenharmony_ci dContext->purgeUnlockedResources(/* scratchResourcesOnly */ true); 1446cb93a386Sopenharmony_ci 1447cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 0); 1448cb93a386Sopenharmony_ci 1449cb93a386Sopenharmony_ci (helper.*addAccess)(helper.ddlCanvas2(), kImageWH, kNoID, false, false); 1450cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (helper.*check)(helper.ddlCanvas2(), kImageWH, 1451cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 2, /*refs*/ 1, kNoID)); 1452cb93a386Sopenharmony_ci sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2(); 1453cb93a386Sopenharmony_ci 1454cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1); 1455cb93a386Sopenharmony_ci 1456cb93a386Sopenharmony_ci helper.checkImage(reporter, std::move(ddl1)); 1457cb93a386Sopenharmony_ci helper.checkImage(reporter, std::move(ddl2)); 1458cb93a386Sopenharmony_ci} 1459cb93a386Sopenharmony_ci 1460cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache15View, reporter, ctxInfo) { 1461cb93a386Sopenharmony_ci test_15(ctxInfo.directContext(), reporter, &TestHelper::addViewAccess, &TestHelper::checkView, 1462cb93a386Sopenharmony_ci create_view_key); 1463cb93a386Sopenharmony_ci} 1464cb93a386Sopenharmony_ci 1465cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache15Verts, reporter, ctxInfo) { 1466cb93a386Sopenharmony_ci test_15(ctxInfo.directContext(), reporter, &TestHelper::addVertAccess, &TestHelper::checkVert, 1467cb93a386Sopenharmony_ci create_vert_key); 1468cb93a386Sopenharmony_ci} 1469cb93a386Sopenharmony_ci 1470cb93a386Sopenharmony_ci// Case 16: Test out pre-emption of an existing vertex-data cache entry. This test simulates 1471cb93a386Sopenharmony_ci// the case where there is a race to create vertex data. However, the second one 1472cb93a386Sopenharmony_ci// to finish is better and usurps the first's position in the cache. 1473cb93a386Sopenharmony_ci// 1474cb93a386Sopenharmony_ci// This capability isn't available for views. 1475cb93a386Sopenharmony_ci 1476cb93a386Sopenharmony_cistatic bool newer_is_always_better(SkData* /* incumbent */, SkData* /* challenger */) { 1477cb93a386Sopenharmony_ci return true; 1478cb93a386Sopenharmony_ci}; 1479cb93a386Sopenharmony_ci 1480cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrThreadSafeCache16Verts, reporter, ctxInfo) { 1481cb93a386Sopenharmony_ci GrUniqueKey key; 1482cb93a386Sopenharmony_ci create_vert_key(&key, kImageWH, kNoID); 1483cb93a386Sopenharmony_ci 1484cb93a386Sopenharmony_ci TestHelper helper(ctxInfo.directContext(), newer_is_always_better); 1485cb93a386Sopenharmony_ci 1486cb93a386Sopenharmony_ci GrThreadSafeVertexTestOp* op1 = nullptr, *op2 = nullptr; 1487cb93a386Sopenharmony_ci 1488cb93a386Sopenharmony_ci helper.addVertAccess(helper.ddlCanvas1(), kImageWH, kNoID, false, false, &op1); 1489cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.checkVert(helper.ddlCanvas1(), kImageWH, 1490cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 1, /*refs*/ 1, kNoID)); 1491cb93a386Sopenharmony_ci sk_sp<SkDeferredDisplayList> ddl1 = helper.snap1(); 1492cb93a386Sopenharmony_ci 1493cb93a386Sopenharmony_ci { 1494cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1); 1495cb93a386Sopenharmony_ci auto [vertexData, xtraData] = helper.threadSafeCache()->findVertsWithData(key); 1496cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, vertexData.get() == op1->vertexData()); 1497cb93a386Sopenharmony_ci } 1498cb93a386Sopenharmony_ci 1499cb93a386Sopenharmony_ci helper.addVertAccess(helper.ddlCanvas2(), kImageWH, kNoID, /* failLookup */ true, false, &op2); 1500cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.checkVert(helper.ddlCanvas2(), kImageWH, 1501cb93a386Sopenharmony_ci /*hits*/ 0, /*misses*/ 2, /*refs*/ 1, kNoID)); 1502cb93a386Sopenharmony_ci sk_sp<SkDeferredDisplayList> ddl2 = helper.snap2(); 1503cb93a386Sopenharmony_ci 1504cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, op1->vertexData() != op2->vertexData()); 1505cb93a386Sopenharmony_ci 1506cb93a386Sopenharmony_ci { 1507cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, helper.numCacheEntries() == 1); 1508cb93a386Sopenharmony_ci auto [vertexData, xtraData] = helper.threadSafeCache()->findVertsWithData(key); 1509cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, vertexData.get() == op2->vertexData()); 1510cb93a386Sopenharmony_ci } 1511cb93a386Sopenharmony_ci 1512cb93a386Sopenharmony_ci helper.checkImage(reporter, std::move(ddl1)); 1513cb93a386Sopenharmony_ci helper.checkImage(reporter, std::move(ddl2)); 1514cb93a386Sopenharmony_ci} 1515