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