• 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/mock/GrMockTypes.h"
11 #include "src/core/SkRectPriv.h"
12 #include "src/gpu/GrClip.h"
13 #include "src/gpu/GrDirectContextPriv.h"
14 #include "src/gpu/GrMemoryPool.h"
15 #include "src/gpu/GrOnFlushResourceProvider.h"
16 #include "src/gpu/GrProxyProvider.h"
17 #include "src/gpu/GrRecordingContextPriv.h"
18 #include "src/gpu/GrResourceProvider.h"
19 #include "src/gpu/GrSurfaceProxy.h"
20 #include "src/gpu/GrSurfaceProxyPriv.h"
21 #include "src/gpu/GrTexture.h"
22 #include "src/gpu/GrTextureProxy.h"
23 #include "src/gpu/GrTextureProxyPriv.h"
24 #include "src/gpu/effects/GrTextureEffect.h"
25 #include "src/gpu/mock/GrMockGpu.h"
26 #include "src/gpu/ops/GrDrawOp.h"
27 #include "src/gpu/v1/SurfaceDrawContext_v1.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 *,SkSpan<const uint32_t>)45     void preFlush(GrOnFlushResourceProvider*, SkSpan<const uint32_t>) override {
46         REPORTER_ASSERT(fReporter, !fHasOpTexture);
47         REPORTER_ASSERT(fReporter, !fHasClipTexture);
48     }
49 
postFlush(GrDeferredUploadToken,SkSpan<const uint32_t>)50     void postFlush(GrDeferredUploadToken, SkSpan<const uint32_t>) override {
51         REPORTER_ASSERT(fReporter, fHasOpTexture);
52         REPORTER_ASSERT(fReporter, fHasClipTexture);
53     }
54 
55     class Op final : public GrDrawOp {
56     public:
57         DEFINE_OP_CLASS_ID
58 
Make(GrRecordingContext * context,GrProxyProvider * proxyProvider,LazyProxyTest * test,bool nullTexture)59         static GrOp::Owner Make(GrRecordingContext* context,
60                                 GrProxyProvider* proxyProvider,
61                                 LazyProxyTest* test,
62                                 bool nullTexture) {
63             return GrOp::Make<Op>(context, context, proxyProvider, test, nullTexture);
64         }
65 
visitProxies(const GrVisitProxyFunc & func) const66         void visitProxies(const GrVisitProxyFunc& func) const override {
67             func(fProxy.get(), GrMipmapped::kNo);
68         }
69 
onExecute(GrOpFlushState *,const SkRect & chainBounds)70         void onExecute(GrOpFlushState*, const SkRect& chainBounds) override {
71             REPORTER_ASSERT(fTest->fReporter, fTest->fHasOpTexture);
72             REPORTER_ASSERT(fTest->fReporter, fTest->fHasClipTexture);
73         }
74 
75     private:
76         friend class GrOp; // for ctor
77 
Op(GrRecordingContext * ctx,GrProxyProvider * proxyProvider,LazyProxyTest * test,bool nullTexture)78         Op(GrRecordingContext* ctx, GrProxyProvider* proxyProvider,
79            LazyProxyTest* test, bool nullTexture)
80                     : GrDrawOp(ClassID()), fTest(test) {
81             const GrBackendFormat format =
82                 ctx->priv().caps()->getDefaultBackendFormat(GrColorType::kBGR_565,
83                                                             GrRenderable::kNo);
84             fProxy = GrProxyProvider::MakeFullyLazyProxy(
85                     [this, nullTexture](GrResourceProvider* rp,
86                                         const GrSurfaceProxy::LazySurfaceDesc& desc)
87                             -> GrSurfaceProxy::LazyCallbackResult {
88                         REPORTER_ASSERT(fTest->fReporter, !fTest->fHasOpTexture);
89                         fTest->fHasOpTexture = true;
90                         if (nullTexture) {
91                             return {};
92                         } else {
93                             static constexpr SkISize kDimensions = {1234, 567};
94                             sk_sp<GrTexture> texture = rp->createTexture(
95                                     kDimensions,
96                                     desc.fFormat,
97                                     desc.fTextureType,
98                                     desc.fRenderable,
99                                     desc.fSampleCnt,
100                                     desc.fMipmapped,
101                                     desc.fBudgeted,
102                                     desc.fProtected);
103                             REPORTER_ASSERT(fTest->fReporter, texture);
104                             return texture;
105                         }
106                     },
107                     format, GrRenderable::kNo, 1, GrProtected::kNo, *proxyProvider->caps(),
108                     GrSurfaceProxy::UseAllocator::kYes);
109 
110             this->setBounds(SkRectPriv::MakeLargest(), GrOp::HasAABloat::kNo,
111                             GrOp::IsHairline::kNo);
112         }
113 
name() const114         const char* name() const override { return "LazyProxyTest::Op"; }
fixedFunctionFlags() const115         FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
finalize(const GrCaps &,const GrAppliedClip * clip,GrClampType)116         GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip* clip,
117                                           GrClampType) override {
118             return GrProcessorSet::EmptySetAnalysis();
119         }
onPrePrepare(GrRecordingContext *,const GrSurfaceProxyView & writeView,GrAppliedClip *,const GrDstProxyView &,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)120         void onPrePrepare(GrRecordingContext*,
121                           const GrSurfaceProxyView& writeView,
122                           GrAppliedClip*,
123                           const GrDstProxyView&,
124                           GrXferBarrierFlags renderPassXferBarriers,
125                           GrLoadOp colorLoadOp) override {}
126 
onPrepare(GrOpFlushState *)127         void onPrepare(GrOpFlushState*) override {}
128 
129         LazyProxyTest* const fTest;
130         sk_sp<GrTextureProxy> fProxy;
131     };
132 
133     class ClipFP : public GrFragmentProcessor {
134     public:
ClipFP(GrRecordingContext * ctx,GrProxyProvider * proxyProvider,LazyProxyTest * test,GrTextureProxy * atlas)135         ClipFP(GrRecordingContext* ctx, GrProxyProvider* proxyProvider, LazyProxyTest* test,
136                GrTextureProxy* atlas)
137                 : GrFragmentProcessor(kTestFP_ClassID, kNone_OptimizationFlags)
138                 , fContext(ctx)
139                 , fProxyProvider(proxyProvider)
140                 , fTest(test)
141                 , fAtlas(atlas) {
142             static const GrColorType kColorType = GrColorType::kAlpha_F16;
143             static const GrSurfaceOrigin kOrigin = kBottomLeft_GrSurfaceOrigin;
144             const GrBackendFormat format =
145                 ctx->priv().caps()->getDefaultBackendFormat(kColorType, GrRenderable::kYes);
146             GrSwizzle readSwizzle = ctx->priv().caps()->getReadSwizzle(format, kColorType);
147             fLazyProxy = GrProxyProvider::MakeFullyLazyProxy(
148                     [this](GrResourceProvider* rp, const GrSurfaceProxy::LazySurfaceDesc&)
149                             -> GrSurfaceProxy::LazyCallbackResult {
150                         REPORTER_ASSERT(fTest->fReporter, !fTest->fHasClipTexture);
151                         fTest->fHasClipTexture = true;
152                         fAtlas->instantiate(rp);
153                         return sk_ref_sp(fAtlas->peekTexture());
154                     },
155                     format, GrRenderable::kYes, 1, GrProtected::kNo, *proxyProvider->caps(),
156                     GrSurfaceProxy::UseAllocator::kYes);
157             auto atlasEffect = GrTextureEffect::Make({fLazyProxy, kOrigin, readSwizzle},
158                                                      kPremul_SkAlphaType);
159             this->registerChild(std::move(atlasEffect));
160         }
161 
162     private:
name() const163         const char* name() const override { return "LazyProxyTest::ClipFP"; }
clone() const164         std::unique_ptr<GrFragmentProcessor> clone() const override {
165             return std::make_unique<ClipFP>(fContext, fProxyProvider, fTest, fAtlas);
166         }
onMakeProgramImpl() const167         std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
168             return nullptr;
169         }
onAddToKey(const GrShaderCaps &,GrProcessorKeyBuilder *) const170         void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
onIsEqual(const GrFragmentProcessor &) const171         bool onIsEqual(const GrFragmentProcessor&) const override { return false; }
172 
173         GrRecordingContext* const fContext;
174         GrProxyProvider* const fProxyProvider;
175         LazyProxyTest* const fTest;
176         GrTextureProxy* const fAtlas;
177         sk_sp<GrTextureProxy> fLazyProxy;
178     };
179 
180 
181     class Clip : public GrClip {
182     public:
Clip(LazyProxyTest * test,GrTextureProxy * atlas)183         Clip(LazyProxyTest* test, GrTextureProxy* atlas)
184                 : fTest(test)
185                 , fAtlas(atlas) {}
186 
187     private:
getConservativeBounds() const188         SkIRect getConservativeBounds() const final {
189             return SkIRect::MakeSize(fAtlas->dimensions());
190         }
apply(GrRecordingContext * rContext,skgpu::v1::SurfaceDrawContext *,GrDrawOp *,GrAAType,GrAppliedClip * out,SkRect * bounds) const191         Effect apply(GrRecordingContext* rContext,
192                      skgpu::v1::SurfaceDrawContext*,
193                      GrDrawOp*,
194                      GrAAType,
195                      GrAppliedClip* out,
196                      SkRect* bounds) const override {
197             GrProxyProvider* proxyProvider = rContext->priv().proxyProvider();
198             out->addCoverageFP(std::make_unique<ClipFP>(rContext, proxyProvider, fTest, fAtlas));
199             return Effect::kClipped;
200         }
201 
202         LazyProxyTest* const fTest;
203         GrTextureProxy* fAtlas;
204     };
205 
206 private:
207     skiatest::Reporter* fReporter;
208     bool fHasOpTexture;
209     bool fHasClipTexture;
210 };
211 
212 DEF_GPUTEST(LazyProxyTest, reporter, /* options */) {
213     GrMockOptions mockOptions;
214     mockOptions.fConfigOptions[(int)GrColorType::kAlpha_F16].fRenderability =
215             GrMockOptions::ConfigOptions::Renderability::kNonMSAA;
216     mockOptions.fConfigOptions[(int)GrColorType::kAlpha_F16].fTexturable = true;
217     sk_sp<GrDirectContext> ctx = GrDirectContext::MakeMock(&mockOptions, GrContextOptions());
218     GrProxyProvider* proxyProvider = ctx->priv().proxyProvider();
219     for (bool nullTexture : {false, true}) {
220         LazyProxyTest test(reporter);
221         ctx->priv().addOnFlushCallbackObject(&test);
222         auto sdc = skgpu::v1::SurfaceDrawContext::Make(ctx.get(), GrColorType::kRGBA_8888, nullptr,
223                                                        SkBackingFit::kExact, {100, 100},
224                                                        SkSurfaceProps());
225         REPORTER_ASSERT(reporter, sdc);
226         auto mockAtlas = skgpu::v1::SurfaceDrawContext::Make(ctx.get(), GrColorType::kAlpha_F16,
227                                                              nullptr, SkBackingFit::kExact,
228                                                              {10, 10}, SkSurfaceProps());
229         REPORTER_ASSERT(reporter, mockAtlas);
230         LazyProxyTest::Clip clip(&test, mockAtlas->asTextureProxy());
231         sdc->addDrawOp(&clip,
232                        LazyProxyTest::Op::Make(ctx.get(), proxyProvider, &test, nullTexture));
233         ctx->priv().testingOnly_flushAndRemoveOnFlushCallbackObject(&test);
234     }
235 }
236 
237 static const int kSize = 16;
238 
239 DEF_GPUTEST(LazyProxyReleaseTest, reporter, /* options */) {
240     GrMockOptions mockOptions;
241     sk_sp<GrDirectContext> ctx = GrDirectContext::MakeMock(&mockOptions, GrContextOptions());
242     auto proxyProvider = ctx->priv().proxyProvider();
243     const GrCaps* caps = ctx->priv().caps();
244 
245     GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888,
246                                                            GrRenderable::kNo);
247 
248     auto tex = ctx->priv().resourceProvider()->createTexture({kSize, kSize},
249                                                              format,
250                                                              GrTextureType::k2D,
251                                                              GrRenderable::kNo,
252                                                              1,
253                                                              GrMipmapped::kNo,
254                                                              SkBudgeted::kNo,
255                                                              GrProtected::kNo);
256     using LazyInstantiationResult = GrSurfaceProxy::LazyCallbackResult;
257     for (bool doInstantiate : {true, false}) {
258         for (bool releaseCallback : {false, true}) {
259             int testCount = 0;
260             // Sets an integer to 1 when the callback is called and -1 when it is deleted.
261             class TestCallback {
262             public:
TestCallback(int * value,bool releaseCallback,sk_sp<GrTexture> tex)263                 TestCallback(int* value, bool releaseCallback, sk_sp<GrTexture> tex)
264                         : fValue(value)
265                         , fReleaseCallback(releaseCallback)
266                         , fTexture(std::move(tex)) {}
TestCallback(const TestCallback & that)267                 TestCallback(const TestCallback& that) { SkASSERT(0); }
TestCallback(TestCallback && that)268                 TestCallback(TestCallback&& that)
269                         : fValue(that.fValue)
270                         , fReleaseCallback(that.fReleaseCallback)
271                         , fTexture(std::move(that.fTexture)) {
272                     that.fValue = nullptr;
273                 }
274 
~TestCallback()275                 ~TestCallback() { fValue ? (void)(*fValue = -1) : void(); }
276 
operator =(TestCallback && that)277                 TestCallback& operator=(TestCallback&& that) {
278                     fValue = std::exchange(that.fValue, nullptr);
279                     return *this;
280                 }
281                 TestCallback& operator=(const TestCallback& that) = delete;
282 
operator ()(GrResourceProvider *,const GrSurfaceProxy::LazySurfaceDesc &) const283                 LazyInstantiationResult operator()(GrResourceProvider*,
284                                                    const GrSurfaceProxy::LazySurfaceDesc&) const {
285                     *fValue = 1;
286                     return {fTexture, fReleaseCallback};
287                 }
288 
289             private:
290                 int* fValue = nullptr;
291                 bool fReleaseCallback;
292                 sk_sp<GrTexture> fTexture;
293             };
294             sk_sp<GrTextureProxy> proxy = proxyProvider->createLazyProxy(
295                     TestCallback(&testCount, releaseCallback, tex), format, {kSize, kSize},
296                     GrMipmapped::kNo, GrMipmapStatus::kNotAllocated, GrInternalSurfaceFlags::kNone,
297                     SkBackingFit::kExact, SkBudgeted::kNo, GrProtected::kNo,
298                     GrSurfaceProxy::UseAllocator::kYes);
299 
300             REPORTER_ASSERT(reporter, proxy.get());
301             REPORTER_ASSERT(reporter, 0 == testCount);
302 
303             if (doInstantiate) {
304                 proxy->priv().doLazyInstantiation(ctx->priv().resourceProvider());
305                 if (releaseCallback) {
306                     // We will call the cleanup and delete the callback in the
307                     // doLazyInstantiationCall.
308                     REPORTER_ASSERT(reporter, -1 == testCount);
309                 } else {
310                     REPORTER_ASSERT(reporter, 1 == testCount);
311                 }
312                 proxy.reset();
313                 REPORTER_ASSERT(reporter, -1 == testCount);
314             } else {
315                 proxy.reset();
316                 REPORTER_ASSERT(reporter, -1 == testCount);
317             }
318         }
319     }
320 }
321 
322 class LazyFailedInstantiationTestOp : public GrDrawOp {
323 public:
324     DEFINE_OP_CLASS_ID
325 
Make(GrRecordingContext * rContext,GrProxyProvider * proxyProvider,int * testExecuteValue,bool shouldFailInstantiation)326     static GrOp::Owner Make(GrRecordingContext* rContext,
327                             GrProxyProvider* proxyProvider,
328                             int* testExecuteValue,
329                             bool shouldFailInstantiation) {
330         return GrOp::Make<LazyFailedInstantiationTestOp>(rContext,
331                                                          rContext->priv().caps(),
332                                                          proxyProvider,
333                                                          testExecuteValue,
334                                                          shouldFailInstantiation);
335     }
336 
visitProxies(const GrVisitProxyFunc & func) const337     void visitProxies(const GrVisitProxyFunc& func) const override {
338         func(fLazyProxy.get(), GrMipmapped::kNo);
339     }
340 
341 private:
342     friend class GrOp; // for ctor
343 
LazyFailedInstantiationTestOp(const GrCaps * caps,GrProxyProvider * proxyProvider,int * testExecuteValue,bool shouldFailInstantiation)344     LazyFailedInstantiationTestOp(const GrCaps* caps, GrProxyProvider* proxyProvider,
345                                   int* testExecuteValue, bool shouldFailInstantiation)
346             : INHERITED(ClassID())
347             , fTestExecuteValue(testExecuteValue) {
348         SkISize dims = {kSize, kSize};
349         GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888,
350                                                                GrRenderable::kNo);
351 
352         fLazyProxy = proxyProvider->createLazyProxy(
353                 [testExecuteValue, shouldFailInstantiation](
354                         GrResourceProvider* rp, const GrSurfaceProxy::LazySurfaceDesc& desc)
355                         -> GrSurfaceProxy::LazyCallbackResult {
356                     if (shouldFailInstantiation) {
357                         *testExecuteValue = 1;
358                         return {};
359                     }
360                     return {rp->createTexture(desc.fDimensions,
361                                               desc.fFormat,
362                                               desc.fTextureType,
363                                               desc.fRenderable,
364                                               desc.fSampleCnt,
365                                               desc.fMipmapped,
366                                               desc.fBudgeted,
367                                               desc.fProtected),
368                             true, GrSurfaceProxy::LazyInstantiationKeyMode::kUnsynced};
369                 },
370                 format, dims, GrMipmapped::kNo, GrMipmapStatus::kNotAllocated,
371                 GrInternalSurfaceFlags::kNone, SkBackingFit::kExact, SkBudgeted::kNo,
372                 GrProtected::kNo, GrSurfaceProxy::UseAllocator::kYes);
373 
374         SkASSERT(fLazyProxy.get());
375 
376         this->setBounds(SkRect::Make(dims), HasAABloat::kNo, IsHairline::kNo);
377     }
378 
name() const379     const char* name() const override { return "LazyFailedInstantiationTestOp"; }
fixedFunctionFlags() const380     FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
finalize(const GrCaps &,const GrAppliedClip *,GrClampType)381     GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override {
382         return GrProcessorSet::EmptySetAnalysis();
383     }
onPrePrepare(GrRecordingContext *,const GrSurfaceProxyView & writeView,GrAppliedClip *,const GrDstProxyView &,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)384     void onPrePrepare(GrRecordingContext*,
385                       const GrSurfaceProxyView& writeView,
386                       GrAppliedClip*,
387                       const GrDstProxyView&,
388                       GrXferBarrierFlags renderPassXferBarriers,
389                       GrLoadOp colorLoadOp) override {}
onPrepare(GrOpFlushState *)390     void onPrepare(GrOpFlushState*) override {}
onExecute(GrOpFlushState * state,const SkRect & chainBounds)391     void onExecute(GrOpFlushState* state, const SkRect& chainBounds) override {
392         *fTestExecuteValue = 2;
393     }
394 
395     int* fTestExecuteValue;
396     sk_sp<GrTextureProxy> fLazyProxy;
397 
398     using INHERITED = GrDrawOp;
399 };
400 
401 // Test that when a lazy proxy fails to instantiate during flush that we drop the Op that it was
402 // associated with.
403 DEF_GPUTEST(LazyProxyFailedInstantiationTest, reporter, /* options */) {
404     GrMockOptions mockOptions;
405     sk_sp<GrDirectContext> ctx = GrDirectContext::MakeMock(&mockOptions, GrContextOptions());
406     GrProxyProvider* proxyProvider = ctx->priv().proxyProvider();
407     for (bool failInstantiation : {false, true}) {
408         auto sdc = skgpu::v1::SurfaceDrawContext::Make(ctx.get(), GrColorType::kRGBA_8888, nullptr,
409                                                        SkBackingFit::kExact, {100, 100},
410                                                        SkSurfaceProps());
411         REPORTER_ASSERT(reporter, sdc);
412 
413         sdc->clear(SkPMColor4f::FromBytes_RGBA(0xbaaaaaad));
414 
415         int executeTestValue = 0;
416         sdc->addDrawOp(LazyFailedInstantiationTestOp::Make(ctx.get(), proxyProvider,
417                                                            &executeTestValue, failInstantiation));
418         ctx->flushAndSubmit();
419 
420         if (failInstantiation) {
421             REPORTER_ASSERT(reporter, 1 == executeTestValue);
422         } else {
423             REPORTER_ASSERT(reporter, 2 == executeTestValue);
424         }
425     }
426 }
427