xref: /aosp_15_r20/external/skia/tests/LazyProxyTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 "include/core/SkAlphaType.h"
9 #include "include/core/SkColorSpace.h"
10 #include "include/core/SkRect.h"
11 #include "include/core/SkRefCnt.h"
12 #include "include/core/SkSize.h"
13 #include "include/core/SkSurfaceProps.h"
14 #include "include/core/SkTypes.h"
15 #include "include/gpu/GpuTypes.h"
16 #include "include/gpu/ganesh/GrBackendSurface.h"
17 #include "include/gpu/ganesh/GrContextOptions.h"
18 #include "include/gpu/ganesh/GrDirectContext.h"
19 #include "include/gpu/ganesh/GrRecordingContext.h"
20 #include "include/gpu/ganesh/GrTypes.h"
21 #include "include/gpu/ganesh/mock/GrMockTypes.h"
22 #include "include/private/SkColorData.h"
23 #include "include/private/gpu/ganesh/GrTypesPriv.h"
24 #include "src/core/SkRectPriv.h"
25 #include "src/gpu/AtlasTypes.h"
26 #include "src/gpu/SkBackingFit.h"
27 #include "src/gpu/Swizzle.h"
28 #include "src/gpu/ganesh/GrAppliedClip.h"
29 #include "src/gpu/ganesh/GrCaps.h"
30 #include "src/gpu/ganesh/GrClip.h"
31 #include "src/gpu/ganesh/GrDirectContextPriv.h"
32 #include "src/gpu/ganesh/GrFragmentProcessor.h"
33 #include "src/gpu/ganesh/GrOnFlushResourceProvider.h"
34 #include "src/gpu/ganesh/GrProcessorSet.h"
35 #include "src/gpu/ganesh/GrProxyProvider.h"
36 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
37 #include "src/gpu/ganesh/GrResourceProvider.h"
38 #include "src/gpu/ganesh/GrSurface.h"
39 #include "src/gpu/ganesh/GrSurfaceProxy.h"
40 #include "src/gpu/ganesh/GrSurfaceProxyPriv.h"
41 #include "src/gpu/ganesh/GrTexture.h"
42 #include "src/gpu/ganesh/GrTextureProxy.h"
43 #include "src/gpu/ganesh/SurfaceDrawContext.h"
44 #include "src/gpu/ganesh/effects/GrTextureEffect.h"
45 #include "src/gpu/ganesh/ops/GrDrawOp.h"
46 #include "src/gpu/ganesh/ops/GrOp.h"
47 #include "tests/CtsEnforcement.h"
48 #include "tests/Test.h"
49 
50 #include <functional>
51 #include <initializer_list>
52 #include <memory>
53 #include <utility>
54 
55 class GrDstProxyView;
56 class GrOpFlushState;
57 class GrSurfaceProxyView;
58 enum class GrXferBarrierFlags;
59 namespace skgpu { class KeyBuilder; }
60 struct GrShaderCaps;
61 
62 // This test verifies that lazy proxy callbacks get invoked during flush, after onFlush callbacks,
63 // but before Ops are executed. It also ensures that lazy proxy callbacks are invoked both for
64 // regular Ops and for clips.
65 class LazyProxyTest final : public GrOnFlushCallbackObject {
66 public:
LazyProxyTest(skiatest::Reporter * reporter)67     LazyProxyTest(skiatest::Reporter* reporter)
68             : fReporter(reporter)
69             , fHasOpTexture(false)
70             , fHasClipTexture(false) {
71     }
72 
~LazyProxyTest()73     ~LazyProxyTest() override {
74         REPORTER_ASSERT(fReporter, fHasOpTexture);
75         REPORTER_ASSERT(fReporter, fHasClipTexture);
76     }
77 
preFlush(GrOnFlushResourceProvider * onFlushRP)78     bool preFlush(GrOnFlushResourceProvider* onFlushRP) override {
79 #if defined(GPU_TEST_UTILS)
80         if (onFlushRP->failFlushTimeCallbacks()) {
81             return false;
82         }
83 #endif
84 
85         REPORTER_ASSERT(fReporter, !fHasOpTexture);
86         REPORTER_ASSERT(fReporter, !fHasClipTexture);
87         return true;
88     }
89 
postFlush(skgpu::AtlasToken)90     void postFlush(skgpu::AtlasToken) override {
91         REPORTER_ASSERT(fReporter, fHasOpTexture);
92         REPORTER_ASSERT(fReporter, fHasClipTexture);
93     }
94 
95     class Op final : public GrDrawOp {
96     public:
97         DEFINE_OP_CLASS_ID
98 
Make(GrRecordingContext * context,GrProxyProvider * proxyProvider,LazyProxyTest * test,bool nullTexture)99         static GrOp::Owner Make(GrRecordingContext* context,
100                                 GrProxyProvider* proxyProvider,
101                                 LazyProxyTest* test,
102                                 bool nullTexture) {
103             return GrOp::Make<Op>(context, context, proxyProvider, test, nullTexture);
104         }
105 
visitProxies(const GrVisitProxyFunc & func) const106         void visitProxies(const GrVisitProxyFunc& func) const override {
107             func(fProxy.get(), skgpu::Mipmapped::kNo);
108         }
109 
onExecute(GrOpFlushState *,const SkRect & chainBounds)110         void onExecute(GrOpFlushState*, const SkRect& chainBounds) override {
111             REPORTER_ASSERT(fTest->fReporter, fTest->fHasOpTexture);
112             REPORTER_ASSERT(fTest->fReporter, fTest->fHasClipTexture);
113         }
114 
115     private:
116         friend class GrOp; // for ctor
117 
Op(GrRecordingContext * ctx,GrProxyProvider * proxyProvider,LazyProxyTest * test,bool nullTexture)118         Op(GrRecordingContext* ctx, GrProxyProvider* proxyProvider,
119            LazyProxyTest* test, bool nullTexture)
120                     : GrDrawOp(ClassID()), fTest(test) {
121             const GrBackendFormat format =
122                 ctx->priv().caps()->getDefaultBackendFormat(GrColorType::kBGR_565,
123                                                             GrRenderable::kNo);
124             fProxy = GrProxyProvider::MakeFullyLazyProxy(
125                     [this, nullTexture](GrResourceProvider* rp,
126                                         const GrSurfaceProxy::LazySurfaceDesc& desc)
127                             -> GrSurfaceProxy::LazyCallbackResult {
128                         REPORTER_ASSERT(fTest->fReporter, !fTest->fHasOpTexture);
129                         fTest->fHasOpTexture = true;
130                         if (nullTexture) {
131                             return {};
132                         } else {
133                             static constexpr SkISize kDimensions = {1234, 567};
134                             sk_sp<GrTexture> texture = rp->createTexture(kDimensions,
135                                                                          desc.fFormat,
136                                                                          desc.fTextureType,
137                                                                          desc.fRenderable,
138                                                                          desc.fSampleCnt,
139                                                                          desc.fMipmapped,
140                                                                          desc.fBudgeted,
141                                                                          desc.fProtected,
142                                                                          /*label=*/{});
143                             REPORTER_ASSERT(fTest->fReporter, texture);
144                             return texture;
145                         }
146                     },
147                     format, GrRenderable::kNo, 1, GrProtected::kNo, *proxyProvider->caps(),
148                     GrSurfaceProxy::UseAllocator::kYes);
149 
150             this->setBounds(SkRectPriv::MakeLargest(), GrOp::HasAABloat::kNo,
151                             GrOp::IsHairline::kNo);
152         }
153 
name() const154         const char* name() const override { return "LazyProxyTest::Op"; }
fixedFunctionFlags() const155         FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
finalize(const GrCaps &,const GrAppliedClip * clip,GrClampType)156         GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip* clip,
157                                           GrClampType) override {
158             return GrProcessorSet::EmptySetAnalysis();
159         }
onPrePrepare(GrRecordingContext *,const GrSurfaceProxyView & writeView,GrAppliedClip *,const GrDstProxyView &,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)160         void onPrePrepare(GrRecordingContext*,
161                           const GrSurfaceProxyView& writeView,
162                           GrAppliedClip*,
163                           const GrDstProxyView&,
164                           GrXferBarrierFlags renderPassXferBarriers,
165                           GrLoadOp colorLoadOp) override {}
166 
onPrepare(GrOpFlushState *)167         void onPrepare(GrOpFlushState*) override {}
168 
169         LazyProxyTest* const fTest;
170         sk_sp<GrTextureProxy> fProxy;
171     };
172 
173     class ClipFP : public GrFragmentProcessor {
174     public:
ClipFP(GrRecordingContext * ctx,GrProxyProvider * proxyProvider,LazyProxyTest * test,GrTextureProxy * atlas)175         ClipFP(GrRecordingContext* ctx, GrProxyProvider* proxyProvider, LazyProxyTest* test,
176                GrTextureProxy* atlas)
177                 : GrFragmentProcessor(kTestFP_ClassID, kNone_OptimizationFlags)
178                 , fContext(ctx)
179                 , fProxyProvider(proxyProvider)
180                 , fTest(test)
181                 , fAtlas(atlas) {
182             static const GrColorType kColorType = GrColorType::kAlpha_F16;
183             static const GrSurfaceOrigin kOrigin = kBottomLeft_GrSurfaceOrigin;
184             const GrBackendFormat format =
185                 ctx->priv().caps()->getDefaultBackendFormat(kColorType, GrRenderable::kYes);
186             skgpu::Swizzle readSwizzle = ctx->priv().caps()->getReadSwizzle(format, kColorType);
187             fLazyProxy = GrProxyProvider::MakeFullyLazyProxy(
188                     [this](GrResourceProvider* rp, const GrSurfaceProxy::LazySurfaceDesc&)
189                             -> GrSurfaceProxy::LazyCallbackResult {
190                         REPORTER_ASSERT(fTest->fReporter, !fTest->fHasClipTexture);
191                         fTest->fHasClipTexture = true;
192                         fAtlas->instantiate(rp);
193                         return sk_ref_sp(fAtlas->peekTexture());
194                     },
195                     format, GrRenderable::kYes, 1, GrProtected::kNo, *proxyProvider->caps(),
196                     GrSurfaceProxy::UseAllocator::kYes);
197             auto atlasEffect = GrTextureEffect::Make({fLazyProxy, kOrigin, readSwizzle},
198                                                      kPremul_SkAlphaType);
199             this->registerChild(std::move(atlasEffect));
200         }
201 
202     private:
name() const203         const char* name() const override { return "LazyProxyTest::ClipFP"; }
clone() const204         std::unique_ptr<GrFragmentProcessor> clone() const override {
205             return std::make_unique<ClipFP>(fContext, fProxyProvider, fTest, fAtlas);
206         }
onMakeProgramImpl() const207         std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
208             return nullptr;
209         }
onAddToKey(const GrShaderCaps &,skgpu::KeyBuilder *) const210         void onAddToKey(const GrShaderCaps&, skgpu::KeyBuilder*) const override {}
onIsEqual(const GrFragmentProcessor &) const211         bool onIsEqual(const GrFragmentProcessor&) const override { return false; }
212 
213         GrRecordingContext* const fContext;
214         GrProxyProvider* const fProxyProvider;
215         LazyProxyTest* const fTest;
216         GrTextureProxy* const fAtlas;
217         sk_sp<GrTextureProxy> fLazyProxy;
218     };
219 
220 
221     class Clip : public GrClip {
222     public:
Clip(LazyProxyTest * test,GrTextureProxy * atlas)223         Clip(LazyProxyTest* test, GrTextureProxy* atlas)
224                 : fTest(test)
225                 , fAtlas(atlas) {}
226 
227     private:
getConservativeBounds() const228         SkIRect getConservativeBounds() const final {
229             return SkIRect::MakeSize(fAtlas->dimensions());
230         }
apply(GrRecordingContext * rContext,skgpu::ganesh::SurfaceDrawContext *,GrDrawOp *,GrAAType,GrAppliedClip * out,SkRect * bounds) const231         Effect apply(GrRecordingContext* rContext,
232                      skgpu::ganesh::SurfaceDrawContext*,
233                      GrDrawOp*,
234                      GrAAType,
235                      GrAppliedClip* out,
236                      SkRect* bounds) const override {
237             GrProxyProvider* proxyProvider = rContext->priv().proxyProvider();
238             out->addCoverageFP(std::make_unique<ClipFP>(rContext, proxyProvider, fTest, fAtlas));
239             return Effect::kClipped;
240         }
241 
242         LazyProxyTest* const fTest;
243         GrTextureProxy* fAtlas;
244     };
245 
246 private:
247     skiatest::Reporter* fReporter;
248     bool fHasOpTexture;
249     bool fHasClipTexture;
250 };
251 
252 DEF_GANESH_TEST(LazyProxyTest, reporter, /* options */, CtsEnforcement::kApiLevel_T) {
253     GrMockOptions mockOptions;
254     mockOptions.fConfigOptions[(int)GrColorType::kAlpha_F16].fRenderability =
255             GrMockOptions::ConfigOptions::Renderability::kNonMSAA;
256     mockOptions.fConfigOptions[(int)GrColorType::kAlpha_F16].fTexturable = true;
257     sk_sp<GrDirectContext> ctx = GrDirectContext::MakeMock(&mockOptions, GrContextOptions());
258     GrProxyProvider* proxyProvider = ctx->priv().proxyProvider();
259     for (bool nullTexture : {false, true}) {
260         LazyProxyTest test(reporter);
261         ctx->priv().addOnFlushCallbackObject(&test);
262         auto sdc = skgpu::ganesh::SurfaceDrawContext::Make(ctx.get(),
263                                                            GrColorType::kRGBA_8888,
264                                                            nullptr,
265                                                            SkBackingFit::kExact,
266                                                            {100, 100},
267                                                            SkSurfaceProps(),
268                                                            /*label=*/{});
269         REPORTER_ASSERT(reporter, sdc);
270         auto mockAtlas = skgpu::ganesh::SurfaceDrawContext::Make(ctx.get(),
271                                                                  GrColorType::kAlpha_F16,
272                                                                  nullptr,
273                                                                  SkBackingFit::kExact,
274                                                                  {10, 10},
275                                                                  SkSurfaceProps(),
276                                                                  /*label=*/{});
277         REPORTER_ASSERT(reporter, mockAtlas);
278         LazyProxyTest::Clip clip(&test, mockAtlas->asTextureProxy());
279         sdc->addDrawOp(&clip,
280                        LazyProxyTest::Op::Make(ctx.get(), proxyProvider, &test, nullTexture));
281         ctx->priv().testingOnly_flushAndRemoveOnFlushCallbackObject(&test);
282     }
283 }
284 
285 static const int kSize = 16;
286 
287 DEF_GANESH_TEST(LazyProxyReleaseTest, reporter, /* options */, CtsEnforcement::kApiLevel_T) {
288     GrMockOptions mockOptions;
289     sk_sp<GrDirectContext> ctx = GrDirectContext::MakeMock(&mockOptions, GrContextOptions());
290     auto proxyProvider = ctx->priv().proxyProvider();
291     const GrCaps* caps = ctx->priv().caps();
292 
293     GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888,
294                                                            GrRenderable::kNo);
295 
296     auto tex = ctx->priv().resourceProvider()->createTexture({kSize, kSize},
297                                                              format,
298                                                              GrTextureType::k2D,
299                                                              GrRenderable::kNo,
300                                                              1,
301                                                              skgpu::Mipmapped::kNo,
302                                                              skgpu::Budgeted::kNo,
303                                                              GrProtected::kNo,
304                                                              /*label=*/{});
305     using LazyInstantiationResult = GrSurfaceProxy::LazyCallbackResult;
306     for (bool doInstantiate : {true, false}) {
307         for (bool releaseCallback : {false, true}) {
308             int testCount = 0;
309             // Sets an integer to 1 when the callback is called and -1 when it is deleted.
310             class TestCallback {
311             public:
TestCallback(int * value,bool releaseCallback,sk_sp<GrTexture> tex)312                 TestCallback(int* value, bool releaseCallback, sk_sp<GrTexture> tex)
313                         : fValue(value)
314                         , fReleaseCallback(releaseCallback)
315                         , fTexture(std::move(tex)) {}
TestCallback(const TestCallback & that)316                 TestCallback(const TestCallback& that) { SkASSERT(0); }
TestCallback(TestCallback && that)317                 TestCallback(TestCallback&& that)
318                         : fValue(that.fValue)
319                         , fReleaseCallback(that.fReleaseCallback)
320                         , fTexture(std::move(that.fTexture)) {
321                     that.fValue = nullptr;
322                 }
323 
~TestCallback()324                 ~TestCallback() { fValue ? (void)(*fValue = -1) : void(); }
325 
operator =(TestCallback && that)326                 TestCallback& operator=(TestCallback&& that) {
327                     fValue = std::exchange(that.fValue, nullptr);
328                     return *this;
329                 }
330                 TestCallback& operator=(const TestCallback& that) = delete;
331 
operator ()(GrResourceProvider *,const GrSurfaceProxy::LazySurfaceDesc &) const332                 LazyInstantiationResult operator()(GrResourceProvider*,
333                                                    const GrSurfaceProxy::LazySurfaceDesc&) const {
334                     *fValue = 1;
335                     return {fTexture, fReleaseCallback};
336                 }
337 
338             private:
339                 int* fValue = nullptr;
340                 bool fReleaseCallback;
341                 sk_sp<GrTexture> fTexture;
342             };
343             sk_sp<GrTextureProxy> proxy =
344                     proxyProvider->createLazyProxy(TestCallback(&testCount, releaseCallback, tex),
345                                                    format,
346                                                    {kSize, kSize},
347                                                    skgpu::Mipmapped::kNo,
348                                                    GrMipmapStatus::kNotAllocated,
349                                                    GrInternalSurfaceFlags::kNone,
350                                                    SkBackingFit::kExact,
351                                                    skgpu::Budgeted::kNo,
352                                                    GrProtected::kNo,
353                                                    GrSurfaceProxy::UseAllocator::kYes,
354                                                    /*label=*/{});
355 
356             REPORTER_ASSERT(reporter, proxy.get());
357             REPORTER_ASSERT(reporter, 0 == testCount);
358 
359             if (doInstantiate) {
360                 proxy->priv().doLazyInstantiation(ctx->priv().resourceProvider());
361                 if (releaseCallback) {
362                     // We will call the cleanup and delete the callback in the
363                     // doLazyInstantiationCall.
364                     REPORTER_ASSERT(reporter, -1 == testCount);
365                 } else {
366                     REPORTER_ASSERT(reporter, 1 == testCount);
367                 }
368                 proxy.reset();
369                 REPORTER_ASSERT(reporter, -1 == testCount);
370             } else {
371                 proxy.reset();
372                 REPORTER_ASSERT(reporter, -1 == testCount);
373             }
374         }
375     }
376 }
377 
378 class LazyFailedInstantiationTestOp : public GrDrawOp {
379 public:
380     DEFINE_OP_CLASS_ID
381 
Make(GrRecordingContext * rContext,GrProxyProvider * proxyProvider,int * testExecuteValue,bool shouldFailInstantiation)382     static GrOp::Owner Make(GrRecordingContext* rContext,
383                             GrProxyProvider* proxyProvider,
384                             int* testExecuteValue,
385                             bool shouldFailInstantiation) {
386         return GrOp::Make<LazyFailedInstantiationTestOp>(rContext,
387                                                          rContext->priv().caps(),
388                                                          proxyProvider,
389                                                          testExecuteValue,
390                                                          shouldFailInstantiation);
391     }
392 
visitProxies(const GrVisitProxyFunc & func) const393     void visitProxies(const GrVisitProxyFunc& func) const override {
394         func(fLazyProxy.get(), skgpu::Mipmapped::kNo);
395     }
396 
397 private:
398     friend class GrOp; // for ctor
399 
LazyFailedInstantiationTestOp(const GrCaps * caps,GrProxyProvider * proxyProvider,int * testExecuteValue,bool shouldFailInstantiation)400     LazyFailedInstantiationTestOp(const GrCaps* caps, GrProxyProvider* proxyProvider,
401                                   int* testExecuteValue, bool shouldFailInstantiation)
402             : INHERITED(ClassID())
403             , fTestExecuteValue(testExecuteValue) {
404         SkISize dims = {kSize, kSize};
405         GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888,
406                                                                GrRenderable::kNo);
407 
408         fLazyProxy = proxyProvider->createLazyProxy(
409                 [testExecuteValue, shouldFailInstantiation](
410                         GrResourceProvider* rp, const GrSurfaceProxy::LazySurfaceDesc& desc)
411                         -> GrSurfaceProxy::LazyCallbackResult {
412                     if (shouldFailInstantiation) {
413                         *testExecuteValue = 1;
414                         return {};
415                     }
416                     return {rp->createTexture(desc.fDimensions,
417                                               desc.fFormat,
418                                               desc.fTextureType,
419                                               desc.fRenderable,
420                                               desc.fSampleCnt,
421                                               desc.fMipmapped,
422                                               desc.fBudgeted,
423                                               desc.fProtected,
424                                               /*label=*/{}),
425                             true, GrSurfaceProxy::LazyInstantiationKeyMode::kUnsynced};
426                 },
427                 format,
428                 dims,
429                 skgpu::Mipmapped::kNo,
430                 GrMipmapStatus::kNotAllocated,
431                 GrInternalSurfaceFlags::kNone,
432                 SkBackingFit::kExact,
433                 skgpu::Budgeted::kNo,
434                 GrProtected::kNo,
435                 GrSurfaceProxy::UseAllocator::kYes,
436                 /*label=*/{});
437 
438         SkASSERT(fLazyProxy.get());
439 
440         this->setBounds(SkRect::Make(dims), HasAABloat::kNo, IsHairline::kNo);
441     }
442 
name() const443     const char* name() const override { return "LazyFailedInstantiationTestOp"; }
fixedFunctionFlags() const444     FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
finalize(const GrCaps &,const GrAppliedClip *,GrClampType)445     GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override {
446         return GrProcessorSet::EmptySetAnalysis();
447     }
onPrePrepare(GrRecordingContext *,const GrSurfaceProxyView & writeView,GrAppliedClip *,const GrDstProxyView &,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)448     void onPrePrepare(GrRecordingContext*,
449                       const GrSurfaceProxyView& writeView,
450                       GrAppliedClip*,
451                       const GrDstProxyView&,
452                       GrXferBarrierFlags renderPassXferBarriers,
453                       GrLoadOp colorLoadOp) override {}
onPrepare(GrOpFlushState *)454     void onPrepare(GrOpFlushState*) override {}
onExecute(GrOpFlushState * state,const SkRect & chainBounds)455     void onExecute(GrOpFlushState* state, const SkRect& chainBounds) override {
456         *fTestExecuteValue = 2;
457     }
458 
459     int* fTestExecuteValue;
460     sk_sp<GrTextureProxy> fLazyProxy;
461 
462     using INHERITED = GrDrawOp;
463 };
464 
465 // Test that when a lazy proxy fails to instantiate during flush that we drop the Op that it was
466 // associated with.
467 DEF_GANESH_TEST(LazyProxyFailedInstantiationTest,
468                 reporter,
469                 /* options */,
470                 CtsEnforcement::kApiLevel_T) {
471     GrMockOptions mockOptions;
472     sk_sp<GrDirectContext> ctx = GrDirectContext::MakeMock(&mockOptions, GrContextOptions());
473     GrProxyProvider* proxyProvider = ctx->priv().proxyProvider();
474     for (bool failInstantiation : {false, true}) {
475         auto sdc = skgpu::ganesh::SurfaceDrawContext::Make(ctx.get(),
476                                                            GrColorType::kRGBA_8888,
477                                                            nullptr,
478                                                            SkBackingFit::kExact,
479                                                            {100, 100},
480                                                            SkSurfaceProps(),
481                                                            /*label=*/{});
482         REPORTER_ASSERT(reporter, sdc);
483 
484         sdc->clear(SkPMColor4f::FromBytes_RGBA(0xbaaaaaad));
485 
486         int executeTestValue = 0;
487         sdc->addDrawOp(LazyFailedInstantiationTestOp::Make(ctx.get(), proxyProvider,
488                                                            &executeTestValue, failInstantiation));
489         ctx->flushAndSubmit();
490 
491         if (failInstantiation) {
492             REPORTER_ASSERT(reporter, 1 == executeTestValue);
493         } else {
494             REPORTER_ASSERT(reporter, 2 == executeTestValue);
495         }
496     }
497 }
498