Home | History | Annotate | Download | only in tests
      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 "Test.h"
      9 
     10 #if SK_SUPPORT_GPU
     11 
     12 #include "GrClip.h"
     13 #include "GrContextPriv.h"
     14 #include "GrProxyProvider.h"
     15 #include "GrOnFlushResourceProvider.h"
     16 #include "GrRenderTargetContext.h"
     17 #include "GrRenderTargetContextPriv.h"
     18 #include "GrSurfaceProxy.h"
     19 #include "GrSurfaceProxyPriv.h"
     20 #include "GrTexture.h"
     21 #include "GrTextureProxy.h"
     22 #include "GrTextureProxyPriv.h"
     23 #include "SkMakeUnique.h"
     24 #include "SkRectPriv.h"
     25 #include "mock/GrMockTypes.h"
     26 
     27 // This test verifies that lazy proxy callbacks get invoked during flush, after onFlush callbacks,
     28 // but before Ops are executed. It also ensures that lazy proxy callbacks are invoked both for
     29 // regular Ops and for clips.
     30 class LazyProxyTest final : public GrOnFlushCallbackObject {
     31 public:
     32     LazyProxyTest(skiatest::Reporter* reporter)
     33             : fReporter(reporter)
     34             , fHasOpTexture(false)
     35             , fHasClipTexture(false) {
     36     }
     37 
     38     ~LazyProxyTest() override {
     39         REPORTER_ASSERT(fReporter, fHasOpTexture);
     40         REPORTER_ASSERT(fReporter, fHasClipTexture);
     41     }
     42 
     43     void preFlush(GrOnFlushResourceProvider*, const uint32_t*, int,
     44                   SkTArray<sk_sp<GrRenderTargetContext>>*) override {
     45         REPORTER_ASSERT(fReporter, !fHasOpTexture);
     46         REPORTER_ASSERT(fReporter, !fHasClipTexture);
     47     }
     48 
     49     void postFlush(GrDeferredUploadToken, const uint32_t* opListIDs, int numOpListIDs) override {
     50         REPORTER_ASSERT(fReporter, fHasOpTexture);
     51         REPORTER_ASSERT(fReporter, fHasClipTexture);
     52     }
     53 
     54     class Op final : public GrDrawOp {
     55     public:
     56         DEFINE_OP_CLASS_ID
     57 
     58         Op(GrProxyProvider* proxyProvider, LazyProxyTest* test, bool nullTexture)
     59                     : GrDrawOp(ClassID()), fTest(test) {
     60             fProxy = proxyProvider->createFullyLazyProxy([this, nullTexture](
     61                                         GrResourceProvider* rp) {
     62                 if (!rp) {
     63                     return sk_sp<GrTexture>();
     64                 }
     65                 REPORTER_ASSERT(fTest->fReporter, !fTest->fHasOpTexture);
     66                 fTest->fHasOpTexture = true;
     67                 if (nullTexture) {
     68                     return sk_sp<GrTexture>();
     69                 } else {
     70                     GrSurfaceDesc desc;
     71                     desc.fWidth = 1234;
     72                     desc.fHeight = 567;
     73                     desc.fOrigin = kTopLeft_GrSurfaceOrigin;
     74                     desc.fConfig = kRGB_565_GrPixelConfig;
     75                     sk_sp<GrTexture> texture = rp->createTexture(desc, SkBudgeted::kYes);
     76                     REPORTER_ASSERT(fTest->fReporter, texture);
     77                     return texture;
     78                 }
     79             }, GrProxyProvider::Renderable::kNo, kTopLeft_GrSurfaceOrigin, kRGB_565_GrPixelConfig);
     80             this->setBounds(SkRectPriv::MakeLargest(), GrOp::HasAABloat::kNo, GrOp::IsZeroArea::kNo);
     81         }
     82 
     83         void visitProxies(const VisitProxyFunc& func) const override {
     84             func(fProxy.get());
     85         }
     86 
     87         void onExecute(GrOpFlushState*) override {
     88             REPORTER_ASSERT(fTest->fReporter, fTest->fHasOpTexture);
     89             REPORTER_ASSERT(fTest->fReporter, fTest->fHasClipTexture);
     90         }
     91 
     92     private:
     93         const char* name() const override { return "LazyProxyTest::Op"; }
     94         FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
     95         RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*,
     96                                     GrPixelConfigIsClamped) override {
     97             return RequiresDstTexture::kNo;
     98         }
     99         void wasRecorded(GrRenderTargetOpList*) override {}
    100         bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; }
    101         void onPrepare(GrOpFlushState*) override {}
    102 
    103         LazyProxyTest* const fTest;
    104         sk_sp<GrTextureProxy> fProxy;
    105     };
    106 
    107     class ClipFP : public GrFragmentProcessor {
    108     public:
    109         ClipFP(GrProxyProvider* proxyProvider, LazyProxyTest* test, GrTextureProxy* atlas)
    110                 : GrFragmentProcessor(kTestFP_ClassID, kNone_OptimizationFlags)
    111                 , fProxyProvider(proxyProvider)
    112                 , fTest(test)
    113                 , fAtlas(atlas) {
    114             fLazyProxy = proxyProvider->createFullyLazyProxy(
    115                                 [this](GrResourceProvider* rp) {
    116                                     if (!rp) {
    117                                         return sk_sp<GrTexture>();
    118                                     }
    119                                     REPORTER_ASSERT(fTest->fReporter, !fTest->fHasClipTexture);
    120                                     fTest->fHasClipTexture = true;
    121                                     fAtlas->instantiate(rp);
    122                                     return sk_ref_sp(fAtlas->priv().peekTexture());
    123                                 },
    124                                 GrProxyProvider::Renderable::kYes,
    125                                 kBottomLeft_GrSurfaceOrigin,
    126                                 kAlpha_half_GrPixelConfig);
    127             fAccess.reset(fLazyProxy, GrSamplerState::Filter::kNearest,
    128                           GrSamplerState::WrapMode::kClamp, kFragment_GrShaderFlag);
    129             this->addTextureSampler(&fAccess);
    130         }
    131 
    132     private:
    133         const char* name() const override { return "LazyProxyTest::ClipFP"; }
    134         std::unique_ptr<GrFragmentProcessor> clone() const override {
    135             return skstd::make_unique<ClipFP>(fProxyProvider, fTest, fAtlas);
    136         }
    137         GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return nullptr; }
    138         void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
    139         bool onIsEqual(const GrFragmentProcessor&) const override { return false; }
    140 
    141         GrProxyProvider* const fProxyProvider;
    142         LazyProxyTest* const fTest;
    143         GrTextureProxy* const fAtlas;
    144         sk_sp<GrTextureProxy> fLazyProxy;
    145         TextureSampler fAccess;
    146     };
    147 
    148 
    149     class Clip : public GrClip {
    150     public:
    151         Clip(LazyProxyTest* test, GrTextureProxy* atlas)
    152                 : fTest(test)
    153                 , fAtlas(atlas) {}
    154 
    155     private:
    156         bool apply(GrContext* context, GrRenderTargetContext*, bool, bool, GrAppliedClip* out,
    157                    SkRect* bounds) const override {
    158             GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
    159             out->addCoverageFP(skstd::make_unique<ClipFP>(proxyProvider, fTest, fAtlas));
    160             return true;
    161         }
    162         bool quickContains(const SkRect&) const final { return false; }
    163         bool isRRect(const SkRect& rtBounds, SkRRect* rr, GrAA*) const final { return false; }
    164         void getConservativeBounds(int width, int height, SkIRect* rect, bool* iior) const final {
    165             rect->set(0, 0, width, height);
    166             if (iior) {
    167                 *iior = false;
    168             }
    169         }
    170 
    171         LazyProxyTest* const fTest;
    172         GrTextureProxy* fAtlas;
    173     };
    174 
    175 private:
    176     skiatest::Reporter* fReporter;
    177     bool fHasOpTexture;
    178     bool fHasClipTexture;
    179 };
    180 
    181 DEF_GPUTEST(LazyProxyTest, reporter, /* options */) {
    182     GrMockOptions mockOptions;
    183     mockOptions.fConfigOptions[kAlpha_half_GrPixelConfig].fRenderability =
    184             GrMockOptions::ConfigOptions::Renderability::kNonMSAA;
    185     mockOptions.fConfigOptions[kAlpha_half_GrPixelConfig].fTexturable = true;
    186     sk_sp<GrContext> ctx = GrContext::MakeMock(&mockOptions, GrContextOptions());
    187     GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();
    188     for (bool nullTexture : {false, true}) {
    189         LazyProxyTest test(reporter);
    190         ctx->contextPriv().addOnFlushCallbackObject(&test);
    191         sk_sp<GrRenderTargetContext> rtc =
    192                 ctx->makeDeferredRenderTargetContext(SkBackingFit::kExact, 100, 100,
    193                                                      kRGBA_8888_GrPixelConfig, nullptr);
    194         REPORTER_ASSERT(reporter, rtc);
    195         sk_sp<GrRenderTargetContext> mockAtlas =
    196                 ctx->makeDeferredRenderTargetContext(SkBackingFit::kExact, 10, 10,
    197                                                      kAlpha_half_GrPixelConfig, nullptr);
    198         REPORTER_ASSERT(reporter, mockAtlas);
    199         rtc->priv().testingOnly_addDrawOp(LazyProxyTest::Clip(&test, mockAtlas->asTextureProxy()),
    200                         skstd::make_unique<LazyProxyTest::Op>(proxyProvider, &test, nullTexture));
    201         ctx->contextPriv().testingOnly_flushAndRemoveOnFlushCallbackObject(&test);
    202     }
    203 }
    204 
    205 static const int kSize = 16;
    206 
    207 DEF_GPUTEST(LazyProxyReleaseTest, reporter, /* options */) {
    208     GrMockOptions mockOptions;
    209     sk_sp<GrContext> ctx = GrContext::MakeMock(&mockOptions, GrContextOptions());
    210     auto proxyProvider = ctx->contextPriv().proxyProvider();
    211 
    212     GrSurfaceDesc desc;
    213     desc.fWidth = kSize;
    214     desc.fHeight = kSize;
    215     desc.fConfig = kRGBA_8888_GrPixelConfig;
    216 
    217     using LazyInstantiationType = GrSurfaceProxy::LazyInstantiationType;
    218     for (bool doInstantiate : {true, false}) {
    219         for (auto lazyType : {LazyInstantiationType::kSingleUse,
    220                               LazyInstantiationType::kMultipleUse}) {
    221             int testCount = 0;
    222             int* testCountPtr = &testCount;
    223             sk_sp<GrTextureProxy> proxy = proxyProvider->createLazyProxy(
    224                     [testCountPtr](GrResourceProvider* resourceProvider) {
    225                         if (!resourceProvider) {
    226                             *testCountPtr = -1;
    227                             return sk_sp<GrTexture>();
    228                         }
    229                         *testCountPtr = 1;
    230                         return sk_sp<GrTexture>();
    231                     }, desc, GrMipMapped::kNo, SkBackingFit::kExact, SkBudgeted::kNo);
    232 
    233             proxy->priv().testingOnly_setLazyInstantiationType(lazyType);
    234 
    235             REPORTER_ASSERT(reporter, 0 == testCount);
    236 
    237             if (doInstantiate) {
    238                 proxy->priv().doLazyInstantiation(ctx->contextPriv().resourceProvider());
    239                 if (LazyInstantiationType::kSingleUse == proxy->priv().lazyInstantiationType()) {
    240                     // In SingleUse we will call the cleanup and delete the callback in the
    241                     // doLazyInstantiationCall.
    242                     REPORTER_ASSERT(reporter, -1 == testCount);
    243                 } else {
    244                     REPORTER_ASSERT(reporter, 1 == testCount);
    245                 }
    246                 proxy.reset();
    247                 REPORTER_ASSERT(reporter, -1 == testCount);
    248             } else {
    249                 proxy.reset();
    250                 REPORTER_ASSERT(reporter, -1 == testCount);
    251             }
    252         }
    253     }
    254 }
    255 
    256 class LazyFailedInstantiationTestOp : public GrDrawOp {
    257 public:
    258     DEFINE_OP_CLASS_ID
    259 
    260     LazyFailedInstantiationTestOp(GrProxyProvider* proxyProvider, int* testExecuteValue,
    261                                   bool shouldFailInstantiation)
    262             : INHERITED(ClassID())
    263             , fTestExecuteValue(testExecuteValue) {
    264         GrSurfaceDesc desc;
    265         desc.fWidth = kSize;
    266         desc.fHeight = kSize;
    267         desc.fConfig = kRGBA_8888_GrPixelConfig;
    268 
    269         fLazyProxy = proxyProvider->createLazyProxy(
    270                 [testExecuteValue, shouldFailInstantiation, desc] (GrResourceProvider* rp) {
    271                     if (!rp) {
    272                         return sk_sp<GrTexture>();
    273                     }
    274                     if (shouldFailInstantiation) {
    275                         *testExecuteValue = 1;
    276                         return sk_sp<GrTexture>();
    277                     }
    278                     return rp->createTexture(desc, SkBudgeted::kNo);
    279                 }, desc, GrMipMapped::kNo, SkBackingFit::kExact, SkBudgeted::kNo);
    280 
    281         this->setBounds(SkRect::MakeIWH(kSize, kSize),
    282                         HasAABloat::kNo, IsZeroArea::kNo);
    283     }
    284 
    285     void visitProxies(const VisitProxyFunc& func) const override {
    286         func(fLazyProxy.get());
    287     }
    288 
    289 private:
    290     const char* name() const override { return "LazyFailedInstantiationTestOp"; }
    291     FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
    292     RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*,
    293                                 GrPixelConfigIsClamped) override {
    294         return RequiresDstTexture::kNo;
    295     }
    296     bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; }
    297     void onPrepare(GrOpFlushState*) override {}
    298     void onExecute(GrOpFlushState* state) override {
    299         *fTestExecuteValue = 2;
    300     }
    301 
    302     int* fTestExecuteValue;
    303     sk_sp<GrSurfaceProxy> fLazyProxy;
    304 
    305     typedef GrDrawOp INHERITED;
    306 };
    307 
    308 // Test that when a lazy proxy fails to instantiate during flush that we drop the Op that it was
    309 // associated with.
    310 DEF_GPUTEST(LazyProxyFailedInstantiationTest, reporter, /* options */) {
    311     GrMockOptions mockOptions;
    312     sk_sp<GrContext> ctx = GrContext::MakeMock(&mockOptions, GrContextOptions());
    313     GrResourceProvider* resourceProvider = ctx->contextPriv().resourceProvider();
    314     GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();
    315     for (bool failInstantiation : {false, true}) {
    316         sk_sp<GrRenderTargetContext> rtc =
    317                 ctx->makeDeferredRenderTargetContext(SkBackingFit::kExact, 100, 100,
    318                                                      kRGBA_8888_GrPixelConfig, nullptr);
    319         REPORTER_ASSERT(reporter, rtc);
    320 
    321         rtc->clear(nullptr, 0xbaaaaaad, GrRenderTargetContext::CanClearFullscreen::kYes);
    322 
    323         int executeTestValue = 0;
    324         rtc->priv().testingOnly_addDrawOp(
    325                 skstd::make_unique<LazyFailedInstantiationTestOp>(proxyProvider, &executeTestValue,
    326                                                                   failInstantiation));
    327         ctx->flush();
    328 
    329         if (failInstantiation) {
    330             if (resourceProvider->explicitlyAllocateGPUResources()) {
    331                 REPORTER_ASSERT(reporter, 1 == executeTestValue);
    332             } else {
    333                 // When we disable explicit gpu resource allocation we don't throw away ops that
    334                 // have uninstantiated proxies.
    335                 REPORTER_ASSERT(reporter, 2 == executeTestValue);
    336             }
    337         } else {
    338             REPORTER_ASSERT(reporter, 2 == executeTestValue);
    339         }
    340     }
    341 
    342 }
    343 
    344 #endif
    345