• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "tests/Test.h"
9 
10 #include "include/gpu/GrTexture.h"
11 #include "include/gpu/mock/GrMockTypes.h"
12 #include "src/core/SkExchange.h"
13 #include "src/core/SkMakeUnique.h"
14 #include "src/core/SkRectPriv.h"
15 #include "src/gpu/GrClip.h"
16 #include "src/gpu/GrContextPriv.h"
17 #include "src/gpu/GrMemoryPool.h"
18 #include "src/gpu/GrOnFlushResourceProvider.h"
19 #include "src/gpu/GrProxyProvider.h"
20 #include "src/gpu/GrRecordingContextPriv.h"
21 #include "src/gpu/GrRenderTargetContext.h"
22 #include "src/gpu/GrRenderTargetContextPriv.h"
23 #include "src/gpu/GrSurfaceProxy.h"
24 #include "src/gpu/GrSurfaceProxyPriv.h"
25 #include "src/gpu/GrTextureProxy.h"
26 #include "src/gpu/GrTextureProxyPriv.h"
27 #include "src/gpu/mock/GrMockGpu.h"
28 
29 // This test verifies that lazy proxy callbacks get invoked during flush, after onFlush callbacks,
30 // but before Ops are executed. It also ensures that lazy proxy callbacks are invoked both for
31 // regular Ops and for clips.
32 class LazyProxyTest final : public GrOnFlushCallbackObject {
33 public:
LazyProxyTest(skiatest::Reporter * reporter)34     LazyProxyTest(skiatest::Reporter* reporter)
35             : fReporter(reporter)
36             , fHasOpTexture(false)
37             , fHasClipTexture(false) {
38     }
39 
~LazyProxyTest()40     ~LazyProxyTest() override {
41         REPORTER_ASSERT(fReporter, fHasOpTexture);
42         REPORTER_ASSERT(fReporter, fHasClipTexture);
43     }
44 
preFlush(GrOnFlushResourceProvider *,const uint32_t *,int,SkTArray<sk_sp<GrRenderTargetContext>> *)45     void preFlush(GrOnFlushResourceProvider*, const uint32_t*, int,
46                   SkTArray<sk_sp<GrRenderTargetContext>>*) override {
47         REPORTER_ASSERT(fReporter, !fHasOpTexture);
48         REPORTER_ASSERT(fReporter, !fHasClipTexture);
49     }
50 
postFlush(GrDeferredUploadToken,const uint32_t * opListIDs,int numOpListIDs)51     void postFlush(GrDeferredUploadToken, const uint32_t* opListIDs, int numOpListIDs) override {
52         REPORTER_ASSERT(fReporter, fHasOpTexture);
53         REPORTER_ASSERT(fReporter, fHasClipTexture);
54     }
55 
56     class Op final : public GrDrawOp {
57     public:
58         DEFINE_OP_CLASS_ID
59 
Make(GrRecordingContext * context,GrProxyProvider * proxyProvider,LazyProxyTest * test,bool nullTexture)60         static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
61                                               GrProxyProvider* proxyProvider,
62                                               LazyProxyTest* test,
63                                               bool nullTexture) {
64             GrOpMemoryPool* pool = context->priv().opMemoryPool();
65 
66             return pool->allocate<Op>(context, proxyProvider, test, nullTexture);
67         }
68 
visitProxies(const VisitProxyFunc & func) const69         void visitProxies(const VisitProxyFunc& func) const override {
70             func(fProxy.get(), GrMipMapped::kNo);
71         }
72 
onExecute(GrOpFlushState *,const SkRect & chainBounds)73         void onExecute(GrOpFlushState*, const SkRect& chainBounds) override {
74             REPORTER_ASSERT(fTest->fReporter, fTest->fHasOpTexture);
75             REPORTER_ASSERT(fTest->fReporter, fTest->fHasClipTexture);
76         }
77 
78     private:
79         friend class GrOpMemoryPool; // for ctor
80 
Op(GrRecordingContext * ctx,GrProxyProvider * proxyProvider,LazyProxyTest * test,bool nullTexture)81         Op(GrRecordingContext* ctx, GrProxyProvider* proxyProvider,
82            LazyProxyTest* test, bool nullTexture)
83                     : GrDrawOp(ClassID()), fTest(test) {
84             const GrBackendFormat format =
85                 ctx->priv().caps()->getDefaultBackendFormat(GrColorType::kBGR_565,
86                                                             GrRenderable::kNo);
87             fProxy = GrProxyProvider::MakeFullyLazyProxy(
88                     [this, format, nullTexture](
89                             GrResourceProvider* rp) -> GrSurfaceProxy::LazyInstantiationResult {
90                         REPORTER_ASSERT(fTest->fReporter, !fTest->fHasOpTexture);
91                         fTest->fHasOpTexture = true;
92                         if (nullTexture) {
93                             return {};
94                         } else {
95                             GrSurfaceDesc desc;
96                             desc.fWidth = 1234;
97                             desc.fHeight = 567;
98                             desc.fConfig = kRGB_565_GrPixelConfig;
99                             sk_sp<GrTexture> texture = rp->createTexture(
100                                     desc, format, GrRenderable::kNo, 1, SkBudgeted::kYes,
101                                     GrProtected::kNo, GrResourceProvider::Flags::kNoPendingIO);
102                             REPORTER_ASSERT(fTest->fReporter, texture);
103                             return texture;
104                         }
105                     },
106                     format, GrRenderable::kNo, 1, GrProtected::kNo, kTopLeft_GrSurfaceOrigin,
107                     kRGB_565_GrPixelConfig, *proxyProvider->caps());
108 
109             this->setBounds(SkRectPriv::MakeLargest(), GrOp::HasAABloat::kNo,
110                             GrOp::IsZeroArea::kNo);
111         }
112 
name() const113         const char* name() const override { return "LazyProxyTest::Op"; }
fixedFunctionFlags() const114         FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
finalize(const GrCaps &,const GrAppliedClip * clip,bool hasMixedSampledCoverage,GrClampType)115         GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip* clip,
116                                           bool hasMixedSampledCoverage, GrClampType) override {
117             return GrProcessorSet::EmptySetAnalysis();
118         }
onPrepare(GrOpFlushState *)119         void onPrepare(GrOpFlushState*) override {}
120 
121         LazyProxyTest* const fTest;
122         sk_sp<GrTextureProxy> fProxy;
123     };
124 
125     class ClipFP : public GrFragmentProcessor {
126     public:
ClipFP(GrRecordingContext * ctx,GrProxyProvider * proxyProvider,LazyProxyTest * test,GrTextureProxy * atlas)127         ClipFP(GrRecordingContext* ctx, GrProxyProvider* proxyProvider, LazyProxyTest* test,
128                GrTextureProxy* atlas)
129                 : GrFragmentProcessor(kTestFP_ClassID, kNone_OptimizationFlags)
130                 , fContext(ctx)
131                 , fProxyProvider(proxyProvider)
132                 , fTest(test)
133                 , fAtlas(atlas) {
134             const GrBackendFormat format =
135                 ctx->priv().caps()->getDefaultBackendFormat(GrColorType::kAlpha_F16,
136                                                             GrRenderable::kYes);
137             fLazyProxy = GrProxyProvider::MakeFullyLazyProxy(
138                     [this](GrResourceProvider* rp) -> GrSurfaceProxy::LazyInstantiationResult {
139                         REPORTER_ASSERT(fTest->fReporter, !fTest->fHasClipTexture);
140                         fTest->fHasClipTexture = true;
141                         fAtlas->instantiate(rp);
142                         return sk_ref_sp(fAtlas->peekTexture());
143                     },
144                     format, GrRenderable::kYes, 1, GrProtected::kNo, kBottomLeft_GrSurfaceOrigin,
145                     kAlpha_half_GrPixelConfig, *proxyProvider->caps());
146             fAccess.reset(fLazyProxy, GrSamplerState::Filter::kNearest,
147                           GrSamplerState::WrapMode::kClamp);
148             this->setTextureSamplerCnt(1);
149         }
150 
151     private:
name() const152         const char* name() const override { return "LazyProxyTest::ClipFP"; }
clone() const153         std::unique_ptr<GrFragmentProcessor> clone() const override {
154             return skstd::make_unique<ClipFP>(fContext, fProxyProvider, fTest, fAtlas);
155         }
onCreateGLSLInstance() const156         GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return nullptr; }
onGetGLSLProcessorKey(const GrShaderCaps &,GrProcessorKeyBuilder *) const157         void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
onIsEqual(const GrFragmentProcessor &) const158         bool onIsEqual(const GrFragmentProcessor&) const override { return false; }
onTextureSampler(int) const159         const TextureSampler& onTextureSampler(int) const override { return fAccess; }
160 
161         GrRecordingContext* const fContext;
162         GrProxyProvider* const fProxyProvider;
163         LazyProxyTest* const fTest;
164         GrTextureProxy* const fAtlas;
165         sk_sp<GrTextureProxy> fLazyProxy;
166         TextureSampler fAccess;
167     };
168 
169 
170     class Clip : public GrClip {
171     public:
Clip(LazyProxyTest * test,GrTextureProxy * atlas)172         Clip(LazyProxyTest* test, GrTextureProxy* atlas)
173                 : fTest(test)
174                 , fAtlas(atlas) {}
175 
176     private:
apply(GrRecordingContext * context,GrRenderTargetContext *,bool useHWAA,bool hasUserStencilSettings,GrAppliedClip * out,SkRect * bounds) const177         bool apply(GrRecordingContext* context, GrRenderTargetContext*, bool useHWAA,
178                    bool hasUserStencilSettings, GrAppliedClip* out, SkRect* bounds) const override {
179             GrProxyProvider* proxyProvider = context->priv().proxyProvider();
180             out->addCoverageFP(skstd::make_unique<ClipFP>(context, proxyProvider, fTest, fAtlas));
181             return true;
182         }
quickContains(const SkRect &) const183         bool quickContains(const SkRect&) const final { return false; }
isRRect(const SkRect & rtBounds,SkRRect * rr,GrAA *) const184         bool isRRect(const SkRect& rtBounds, SkRRect* rr, GrAA*) const final { return false; }
getConservativeBounds(int width,int height,SkIRect * rect,bool * iior) const185         void getConservativeBounds(int width, int height, SkIRect* rect, bool* iior) const final {
186             rect->set(0, 0, width, height);
187             if (iior) {
188                 *iior = false;
189             }
190         }
191 
192         LazyProxyTest* const fTest;
193         GrTextureProxy* fAtlas;
194     };
195 
196 private:
197     skiatest::Reporter* fReporter;
198     bool fHasOpTexture;
199     bool fHasClipTexture;
200 };
201 
202 DEF_GPUTEST(LazyProxyTest, reporter, /* options */) {
203     GrMockOptions mockOptions;
204     mockOptions.fConfigOptions[(int)GrColorType::kAlpha_F16].fRenderability =
205             GrMockOptions::ConfigOptions::Renderability::kNonMSAA;
206     mockOptions.fConfigOptions[(int)GrColorType::kAlpha_F16].fTexturable = true;
207     sk_sp<GrContext> ctx = GrContext::MakeMock(&mockOptions, GrContextOptions());
208     GrProxyProvider* proxyProvider = ctx->priv().proxyProvider();
209     for (bool nullTexture : {false, true}) {
210         LazyProxyTest test(reporter);
211         ctx->priv().addOnFlushCallbackObject(&test);
212         sk_sp<GrRenderTargetContext> rtc = ctx->priv().makeDeferredRenderTargetContext(
213                 SkBackingFit::kExact, 100, 100, GrColorType::kRGBA_8888, nullptr);
214         REPORTER_ASSERT(reporter, rtc);
215         sk_sp<GrRenderTargetContext> mockAtlas = ctx->priv().makeDeferredRenderTargetContext(
216                 SkBackingFit::kExact, 10, 10, GrColorType::kAlpha_F16, nullptr);
217         REPORTER_ASSERT(reporter, mockAtlas);
218         rtc->priv().testingOnly_addDrawOp(LazyProxyTest::Clip(&test, mockAtlas->asTextureProxy()),
219                         LazyProxyTest::Op::Make(ctx.get(), proxyProvider, &test, nullTexture));
220         ctx->priv().testingOnly_flushAndRemoveOnFlushCallbackObject(&test);
221     }
222 }
223 
224 static const int kSize = 16;
225 
226 DEF_GPUTEST(LazyProxyReleaseTest, reporter, /* options */) {
227     GrMockOptions mockOptions;
228     sk_sp<GrContext> ctx = GrContext::MakeMock(&mockOptions, GrContextOptions());
229     auto proxyProvider = ctx->priv().proxyProvider();
230     const GrCaps* caps = ctx->priv().caps();
231 
232     GrSurfaceDesc desc;
233     desc.fWidth = kSize;
234     desc.fHeight = kSize;
235     desc.fConfig = kRGBA_8888_GrPixelConfig;
236 
237     GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888,
238                                                            GrRenderable::kNo);
239 
240     using LazyInstantiationType = GrSurfaceProxy::LazyInstantiationType;
241     using LazyInstantiationResult = GrSurfaceProxy::LazyInstantiationResult;
242     for (bool doInstantiate : {true, false}) {
243         for (auto lazyType : {LazyInstantiationType::kSingleUse,
244                               LazyInstantiationType::kMultipleUse,
245                               LazyInstantiationType::kDeinstantiate}) {
246             int testCount = 0;
247             // Sets an integer to 1 when the callback is called and -1 when it is deleted.
248             class TestCallback {
249             public:
TestCallback(int * value)250                 TestCallback(int* value) : fValue(value) {}
TestCallback(const TestCallback & that)251                 TestCallback(const TestCallback& that) { SkASSERT(0); }
TestCallback(TestCallback && that)252                 TestCallback(TestCallback&& that) : fValue(that.fValue) { that.fValue = nullptr; }
253 
~TestCallback()254                 ~TestCallback() { fValue ? (void)(*fValue = -1) : void(); }
255 
operator =(TestCallback && that)256                 TestCallback& operator=(TestCallback&& that) {
257                     fValue = skstd::exchange(that.fValue, nullptr);
258                     return *this;
259                 }
260                 TestCallback& operator=(const TestCallback& that) = delete;
261 
operator ()(GrResourceProvider * resourceProvider) const262                 LazyInstantiationResult operator()(GrResourceProvider* resourceProvider) const {
263                     *fValue = 1;
264                     return {};
265                 }
266 
267             private:
268                 int* fValue = nullptr;
269             };
270             sk_sp<GrTextureProxy> proxy = proxyProvider->createLazyProxy(
271                     TestCallback(&testCount), format, desc, GrRenderable::kNo, 1,
272                     kTopLeft_GrSurfaceOrigin, GrMipMapped::kNo, GrMipMapsStatus::kNotAllocated,
273                     GrInternalSurfaceFlags::kNone, SkBackingFit::kExact, SkBudgeted::kNo,
274                     GrProtected::kNo, lazyType);
275 
276             REPORTER_ASSERT(reporter, proxy.get());
277             REPORTER_ASSERT(reporter, 0 == testCount);
278 
279             if (doInstantiate) {
280                 proxy->priv().doLazyInstantiation(ctx->priv().resourceProvider());
281                 if (LazyInstantiationType::kSingleUse == proxy->priv().lazyInstantiationType()) {
282                     // In SingleUse we will call the cleanup and delete the callback in the
283                     // doLazyInstantiationCall.
284                     REPORTER_ASSERT(reporter, -1 == testCount);
285                 } else {
286                     REPORTER_ASSERT(reporter, 1 == testCount);
287                 }
288                 proxy.reset();
289                 REPORTER_ASSERT(reporter, -1 == testCount);
290             } else {
291                 proxy.reset();
292                 REPORTER_ASSERT(reporter, -1 == testCount);
293             }
294         }
295     }
296 }
297 
298 class LazyFailedInstantiationTestOp : public GrDrawOp {
299 public:
300     DEFINE_OP_CLASS_ID
301 
Make(GrContext * context,GrProxyProvider * proxyProvider,int * testExecuteValue,bool shouldFailInstantiation)302     static std::unique_ptr<GrDrawOp> Make(GrContext* context,
303                                           GrProxyProvider* proxyProvider,
304                                           int* testExecuteValue,
305                                           bool shouldFailInstantiation) {
306         GrOpMemoryPool* pool = context->priv().opMemoryPool();
307 
308         return pool->allocate<LazyFailedInstantiationTestOp>(context, proxyProvider,
309                                                              testExecuteValue,
310                                                              shouldFailInstantiation);
311     }
312 
visitProxies(const VisitProxyFunc & func) const313     void visitProxies(const VisitProxyFunc& func) const override {
314         func(fLazyProxy.get(), GrMipMapped::kNo);
315     }
316 
317 private:
318     friend class GrOpMemoryPool; // for ctor
319 
LazyFailedInstantiationTestOp(GrContext * ctx,GrProxyProvider * proxyProvider,int * testExecuteValue,bool shouldFailInstantiation)320     LazyFailedInstantiationTestOp(GrContext* ctx, GrProxyProvider* proxyProvider,
321                                   int* testExecuteValue, bool shouldFailInstantiation)
322             : INHERITED(ClassID())
323             , fTestExecuteValue(testExecuteValue) {
324         GrSurfaceDesc desc;
325         desc.fWidth = kSize;
326         desc.fHeight = kSize;
327         desc.fConfig = kRGBA_8888_GrPixelConfig;
328         GrBackendFormat format =
329             ctx->priv().caps()->getDefaultBackendFormat(GrColorType::kRGBA_8888,
330                                                         GrRenderable::kNo);
331 
332         fLazyProxy = proxyProvider->createLazyProxy(
333                 [testExecuteValue, shouldFailInstantiation, desc,
334                  format](GrResourceProvider* rp) -> GrSurfaceProxy::LazyInstantiationResult {
335                     if (shouldFailInstantiation) {
336                         *testExecuteValue = 1;
337                         return {};
338                     }
339                     return {rp->createTexture(desc, format, GrRenderable::kNo, 1, SkBudgeted::kNo,
340                                               GrProtected::kNo,
341                                               GrResourceProvider::Flags::kNoPendingIO),
342                             GrSurfaceProxy::LazyInstantiationKeyMode::kUnsynced};
343                 },
344                 format, desc, GrRenderable::kNo, 1, kTopLeft_GrSurfaceOrigin, GrMipMapped::kNo,
345                 GrMipMapsStatus::kNotAllocated, SkBackingFit::kExact, SkBudgeted::kNo,
346                 GrProtected::kNo);
347 
348         SkASSERT(fLazyProxy.get());
349 
350         this->setBounds(SkRect::MakeIWH(kSize, kSize),
351                         HasAABloat::kNo, IsZeroArea::kNo);
352     }
353 
name() const354     const char* name() const override { return "LazyFailedInstantiationTestOp"; }
fixedFunctionFlags() const355     FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
finalize(const GrCaps &,const GrAppliedClip *,bool hasMixedSampledCoverage,GrClampType)356     GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*,
357                                       bool hasMixedSampledCoverage, GrClampType) override {
358         return GrProcessorSet::EmptySetAnalysis();
359     }
onPrepare(GrOpFlushState *)360     void onPrepare(GrOpFlushState*) override {}
onExecute(GrOpFlushState * state,const SkRect & chainBounds)361     void onExecute(GrOpFlushState* state, const SkRect& chainBounds) override {
362         *fTestExecuteValue = 2;
363     }
364 
365     int* fTestExecuteValue;
366     sk_sp<GrSurfaceProxy> fLazyProxy;
367 
368     typedef GrDrawOp INHERITED;
369 };
370 
371 // Test that when a lazy proxy fails to instantiate during flush that we drop the Op that it was
372 // associated with.
373 DEF_GPUTEST(LazyProxyFailedInstantiationTest, reporter, /* options */) {
374     GrMockOptions mockOptions;
375     sk_sp<GrContext> ctx = GrContext::MakeMock(&mockOptions, GrContextOptions());
376     GrProxyProvider* proxyProvider = ctx->priv().proxyProvider();
377     for (bool failInstantiation : {false, true}) {
378         sk_sp<GrRenderTargetContext> rtc = ctx->priv().makeDeferredRenderTargetContext(
379                 SkBackingFit::kExact, 100, 100, GrColorType::kRGBA_8888, nullptr);
380         REPORTER_ASSERT(reporter, rtc);
381 
382         rtc->clear(nullptr, SkPMColor4f::FromBytes_RGBA(0xbaaaaaad),
383                    GrRenderTargetContext::CanClearFullscreen::kYes);
384 
385         int executeTestValue = 0;
386         rtc->priv().testingOnly_addDrawOp(LazyFailedInstantiationTestOp::Make(
387                 ctx.get(), proxyProvider, &executeTestValue, failInstantiation));
388         ctx->flush();
389 
390         if (failInstantiation) {
391             REPORTER_ASSERT(reporter, 1 == executeTestValue);
392         } else {
393             REPORTER_ASSERT(reporter, 2 == executeTestValue);
394         }
395     }
396 }
397 
398 class LazyDeinstantiateTestOp : public GrDrawOp {
399 public:
400     DEFINE_OP_CLASS_ID
401 
Make(GrContext * context,sk_sp<GrTextureProxy> proxy)402     static std::unique_ptr<GrDrawOp> Make(GrContext* context, sk_sp<GrTextureProxy> proxy) {
403         GrOpMemoryPool* pool = context->priv().opMemoryPool();
404 
405         return pool->allocate<LazyDeinstantiateTestOp>(std::move(proxy));
406     }
407 
visitProxies(const VisitProxyFunc & func) const408     void visitProxies(const VisitProxyFunc& func) const override {
409         func(fLazyProxy.get(), GrMipMapped::kNo);
410     }
411 
412 private:
413     friend class GrOpMemoryPool; // for ctor
414 
LazyDeinstantiateTestOp(sk_sp<GrTextureProxy> proxy)415     LazyDeinstantiateTestOp(sk_sp<GrTextureProxy> proxy)
416             : INHERITED(ClassID()), fLazyProxy(std::move(proxy)) {
417         this->setBounds(SkRect::MakeIWH(kSize, kSize), HasAABloat::kNo, IsZeroArea::kNo);
418     }
419 
name() const420     const char* name() const override { return "LazyDeinstantiateTestOp"; }
fixedFunctionFlags() const421     FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
finalize(const GrCaps &,const GrAppliedClip *,bool hasMixedSampledCoverage,GrClampType)422     GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*,
423                                       bool hasMixedSampledCoverage, GrClampType) override {
424         return GrProcessorSet::EmptySetAnalysis();
425     }
onPrepare(GrOpFlushState *)426     void onPrepare(GrOpFlushState*) override {}
onExecute(GrOpFlushState * state,const SkRect & chainBounds)427     void onExecute(GrOpFlushState* state, const SkRect& chainBounds) override {}
428 
429     sk_sp<GrSurfaceProxy> fLazyProxy;
430 
431     typedef GrDrawOp INHERITED;
432 };
433 
DeinstantiateReleaseProc(void * releaseValue)434 static void DeinstantiateReleaseProc(void* releaseValue) { (*static_cast<int*>(releaseValue))++; }
435 
436 // Test that lazy proxies with the Deinstantiate LazyCallbackType are deinstantiated and released as
437 // expected.
438 DEF_GPUTEST(LazyProxyDeinstantiateTest, reporter, /* options */) {
439     GrMockOptions mockOptions;
440     sk_sp<GrContext> ctx = GrContext::MakeMock(&mockOptions, GrContextOptions());
441     GrProxyProvider* proxyProvider = ctx->priv().proxyProvider();
442 
443     GrBackendFormat format =
444         ctx->priv().caps()->getDefaultBackendFormat(GrColorType::kRGBA_8888,
445                                                     GrRenderable::kNo);
446 
447     using LazyType = GrSurfaceProxy::LazyInstantiationType;
448     for (auto lazyType : {LazyType::kSingleUse, LazyType::kMultipleUse, LazyType::kDeinstantiate}) {
449         sk_sp<GrRenderTargetContext> rtc = ctx->priv().makeDeferredRenderTargetContext(
450                 SkBackingFit::kExact, 100, 100, GrColorType::kRGBA_8888, nullptr);
451         REPORTER_ASSERT(reporter, rtc);
452 
453         rtc->clear(nullptr, SkPMColor4f::FromBytes_RGBA(0xbaaaaaad),
454                    GrRenderTargetContext::CanClearFullscreen::kYes);
455 
456         int instantiateTestValue = 0;
457         int releaseTestValue = 0;
458         int* instantiatePtr = &instantiateTestValue;
459         int* releasePtr = &releaseTestValue;
460         GrSurfaceDesc desc;
461         desc.fWidth = kSize;
462         desc.fHeight = kSize;
463         desc.fConfig = kRGBA_8888_GrPixelConfig;
464 
465         GrBackendTexture backendTex = ctx->createBackendTexture(
466                 kSize, kSize, kRGBA_8888_SkColorType, SkColors::kTransparent,
467                 GrMipMapped::kNo, GrRenderable::kNo, GrProtected::kNo);
468 
469         sk_sp<GrTextureProxy> lazyProxy = proxyProvider->createLazyProxy(
470                 [instantiatePtr, releasePtr,
__anonfa3c11a50402(GrResourceProvider* rp) 471                  backendTex](GrResourceProvider* rp) -> GrSurfaceProxy::LazyInstantiationResult {
472                     sk_sp<GrTexture> texture =
473                             rp->wrapBackendTexture(backendTex, GrColorType::kRGBA_8888,
474                                                    kBorrow_GrWrapOwnership, GrWrapCacheable::kNo,
475                                                    kRead_GrIOType);
476                     if (!texture) {
477                         return {};
478                     }
479                     (*instantiatePtr)++;
480                     texture->setRelease(DeinstantiateReleaseProc, releasePtr);
481                     return texture;
482                 },
483                 format, desc, GrRenderable::kNo, 1, kTopLeft_GrSurfaceOrigin, GrMipMapped::kNo,
484                 GrMipMapsStatus::kNotAllocated, GrInternalSurfaceFlags::kReadOnly,
485                 SkBackingFit::kExact, SkBudgeted::kNo, GrProtected::kNo, lazyType);
486 
487         REPORTER_ASSERT(reporter, lazyProxy.get());
488 
489         rtc->priv().testingOnly_addDrawOp(LazyDeinstantiateTestOp::Make(ctx.get(), lazyProxy));
490 
491         ctx->flush();
492 
493         REPORTER_ASSERT(reporter, 1 == instantiateTestValue);
494         if (LazyType::kDeinstantiate == lazyType) {
495             REPORTER_ASSERT(reporter, 1 == releaseTestValue);
496         } else {
497             REPORTER_ASSERT(reporter, 0 == releaseTestValue);
498         }
499 
500         // This should cause the uninstantiate proxies to be instantiated again but have no effect
501         // on the others
502         rtc->priv().testingOnly_addDrawOp(LazyDeinstantiateTestOp::Make(ctx.get(), lazyProxy));
503         // Add a second op to make sure we only instantiate once.
504         rtc->priv().testingOnly_addDrawOp(LazyDeinstantiateTestOp::Make(ctx.get(), lazyProxy));
505         ctx->flush();
506 
507         if (LazyType::kDeinstantiate == lazyType) {
508             REPORTER_ASSERT(reporter, 2 == instantiateTestValue);
509             REPORTER_ASSERT(reporter, 2 == releaseTestValue);
510         } else {
511             REPORTER_ASSERT(reporter, 1 == instantiateTestValue);
512             REPORTER_ASSERT(reporter, 0 == releaseTestValue);
513         }
514 
515         lazyProxy.reset();
516         if (LazyType::kDeinstantiate == lazyType) {
517             REPORTER_ASSERT(reporter, 2 == releaseTestValue);
518         } else {
519             REPORTER_ASSERT(reporter, 1 == releaseTestValue);
520         }
521 
522         ctx->deleteBackendTexture(backendTex);
523     }
524 }
525