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, GrSurfaceOrigin* origin) {
     62                 if (!rp) {
     63                     return sk_sp<GrTexture>();
     64                 }
     65                 REPORTER_ASSERT(fTest->fReporter, !fTest->fHasOpTexture);
     66                 fTest->fHasOpTexture = true;
     67                 *origin = kTopLeft_GrSurfaceOrigin;
     68                 if (nullTexture) {
     69                     return sk_sp<GrTexture>();
     70                 } else {
     71                     GrSurfaceDesc desc;
     72                     desc.fWidth = 1234;
     73                     desc.fHeight = 567;
     74                     desc.fOrigin = kTopLeft_GrSurfaceOrigin;
     75                     desc.fConfig = kRGB_565_GrPixelConfig;
     76                     sk_sp<GrTexture> texture = rp->createTexture(desc, SkBudgeted::kYes);
     77                     REPORTER_ASSERT(fTest->fReporter, texture);
     78                     return texture;
     79                 }
     80             }, GrProxyProvider::Renderable::kNo, kRGB_565_GrPixelConfig);
     81             this->setBounds(SkRectPriv::MakeLargest(), GrOp::HasAABloat::kNo, GrOp::IsZeroArea::kNo);
     82         }
     83 
     84         void visitProxies(const VisitProxyFunc& func) const override {
     85             func(fProxy.get());
     86         }
     87 
     88         void onExecute(GrOpFlushState*) override {
     89             REPORTER_ASSERT(fTest->fReporter, fTest->fHasOpTexture);
     90             REPORTER_ASSERT(fTest->fReporter, fTest->fHasClipTexture);
     91         }
     92 
     93     private:
     94         const char* name() const override { return "LazyProxyTest::Op"; }
     95         FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
     96         RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*,
     97                                     GrPixelConfigIsClamped) override {
     98             return RequiresDstTexture::kNo;
     99         }
    100         void wasRecorded(GrRenderTargetOpList*) override {}
    101         bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; }
    102         void onPrepare(GrOpFlushState*) override {}
    103 
    104         LazyProxyTest* const fTest;
    105         sk_sp<GrTextureProxy> fProxy;
    106     };
    107 
    108     class ClipFP : public GrFragmentProcessor {
    109     public:
    110         ClipFP(GrProxyProvider* proxyProvider, LazyProxyTest* test, GrTextureProxy* atlas)
    111                 : GrFragmentProcessor(kTestFP_ClassID, kNone_OptimizationFlags)
    112                 , fProxyProvider(proxyProvider)
    113                 , fTest(test)
    114                 , fAtlas(atlas) {
    115             fLazyProxy = proxyProvider->createFullyLazyProxy([this](GrResourceProvider* rp,
    116                                                                     GrSurfaceOrigin* origin) {
    117                 if (!rp) {
    118                     return sk_sp<GrTexture>();
    119                 }
    120                 REPORTER_ASSERT(fTest->fReporter, !fTest->fHasClipTexture);
    121                 fTest->fHasClipTexture = true;
    122                 *origin = kBottomLeft_GrSurfaceOrigin;
    123                 fAtlas->instantiate(rp);
    124                 return sk_ref_sp(fAtlas->priv().peekTexture());
    125             }, GrProxyProvider::Renderable::kYes, kAlpha_half_GrPixelConfig);
    126             fAccess.reset(fLazyProxy, GrSamplerState::Filter::kNearest,
    127                           GrSamplerState::WrapMode::kClamp, kFragment_GrShaderFlag);
    128             this->addTextureSampler(&fAccess);
    129         }
    130 
    131     private:
    132         const char* name() const override { return "LazyProxyTest::ClipFP"; }
    133         std::unique_ptr<GrFragmentProcessor> clone() const override {
    134             return skstd::make_unique<ClipFP>(fProxyProvider, fTest, fAtlas);
    135         }
    136         GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return nullptr; }
    137         void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
    138         bool onIsEqual(const GrFragmentProcessor&) const override { return false; }
    139 
    140         GrProxyProvider* const fProxyProvider;
    141         LazyProxyTest* const fTest;
    142         GrTextureProxy* const fAtlas;
    143         sk_sp<GrTextureProxy> fLazyProxy;
    144         TextureSampler fAccess;
    145     };
    146 
    147 
    148     class Clip : public GrClip {
    149     public:
    150         Clip(LazyProxyTest* test, GrTextureProxy* atlas)
    151                 : fTest(test)
    152                 , fAtlas(atlas) {}
    153 
    154     private:
    155         bool apply(GrContext* context, GrRenderTargetContext*, bool, bool, GrAppliedClip* out,
    156                    SkRect* bounds) const override {
    157             GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
    158             out->addCoverageFP(skstd::make_unique<ClipFP>(proxyProvider, fTest, fAtlas));
    159             return true;
    160         }
    161         bool quickContains(const SkRect&) const final { return false; }
    162         bool isRRect(const SkRect& rtBounds, SkRRect* rr, GrAA*) const final { return false; }
    163         void getConservativeBounds(int width, int height, SkIRect* rect, bool* iior) const final {
    164             rect->set(0, 0, width, height);
    165             if (iior) {
    166                 *iior = false;
    167             }
    168         }
    169 
    170         LazyProxyTest* const fTest;
    171         GrTextureProxy* fAtlas;
    172     };
    173 
    174 private:
    175     skiatest::Reporter* fReporter;
    176     bool fHasOpTexture;
    177     bool fHasClipTexture;
    178 };
    179 
    180 DEF_GPUTEST(LazyProxyTest, reporter, /* options */) {
    181     GrMockOptions mockOptions;
    182     mockOptions.fConfigOptions[kAlpha_half_GrPixelConfig].fRenderable[0] = true;
    183     mockOptions.fConfigOptions[kAlpha_half_GrPixelConfig].fTexturable = true;
    184     sk_sp<GrContext> ctx = GrContext::MakeMock(&mockOptions, GrContextOptions());
    185     GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();
    186     for (bool nullTexture : {false, true}) {
    187         LazyProxyTest test(reporter);
    188         ctx->contextPriv().addOnFlushCallbackObject(&test);
    189         sk_sp<GrRenderTargetContext> rtc =
    190                 ctx->makeDeferredRenderTargetContext(SkBackingFit::kExact, 100, 100,
    191                                                      kRGBA_8888_GrPixelConfig, nullptr);
    192         REPORTER_ASSERT(reporter, rtc);
    193         sk_sp<GrRenderTargetContext> mockAtlas =
    194                 ctx->makeDeferredRenderTargetContext(SkBackingFit::kExact, 10, 10,
    195                                                      kAlpha_half_GrPixelConfig, nullptr);
    196         REPORTER_ASSERT(reporter, mockAtlas);
    197         rtc->priv().testingOnly_addDrawOp(LazyProxyTest::Clip(&test, mockAtlas->asTextureProxy()),
    198                         skstd::make_unique<LazyProxyTest::Op>(proxyProvider, &test, nullTexture));
    199         ctx->contextPriv().testingOnly_flushAndRemoveOnFlushCallbackObject(&test);
    200     }
    201 }
    202 
    203 static const int kSize = 16;
    204 
    205 DEF_GPUTEST(LazyProxyReleaseTest, reporter, /* options */) {
    206     GrMockOptions mockOptions;
    207     sk_sp<GrContext> ctx = GrContext::MakeMock(&mockOptions, GrContextOptions());
    208     auto proxyProvider = ctx->contextPriv().proxyProvider();
    209 
    210     GrSurfaceDesc desc;
    211     desc.fWidth = kSize;
    212     desc.fHeight = kSize;
    213     desc.fConfig = kRGBA_8888_GrPixelConfig;
    214 
    215     for (bool doInstantiate : {true, false}) {
    216         int testCount = 0;
    217         int* testCountPtr = &testCount;
    218         sk_sp<GrTextureProxy> proxy = proxyProvider->createLazyProxy(
    219                 [testCountPtr](GrResourceProvider* resourceProvider, GrSurfaceOrigin* outOrigin) {
    220                     if (!resourceProvider) {
    221                         *testCountPtr = -1;
    222                         return sk_sp<GrTexture>();
    223                     }
    224                     *testCountPtr = 1;
    225                     return sk_sp<GrTexture>();
    226                 }, desc, GrMipMapped::kNo, SkBackingFit::kExact, SkBudgeted::kNo);
    227 
    228         REPORTER_ASSERT(reporter, 0 == testCount);
    229 
    230         if (doInstantiate) {
    231             proxy->priv().doLazyInstantiation(ctx->contextPriv().resourceProvider());
    232             REPORTER_ASSERT(reporter, 1 == testCount);
    233             proxy.reset();
    234             REPORTER_ASSERT(reporter, -1 == testCount);
    235         } else {
    236             proxy.reset();
    237             REPORTER_ASSERT(reporter, -1 == testCount);
    238         }
    239     }
    240 }
    241 
    242 class LazyFailedInstantiationTestOp : public GrDrawOp {
    243 public:
    244     DEFINE_OP_CLASS_ID
    245 
    246     LazyFailedInstantiationTestOp(GrProxyProvider* proxyProvider, int* testExecuteValue,
    247                                   bool shouldFailInstantiation)
    248             : INHERITED(ClassID())
    249             , fTestExecuteValue(testExecuteValue) {
    250         GrSurfaceDesc desc;
    251         desc.fWidth = kSize;
    252         desc.fHeight = kSize;
    253         desc.fConfig = kRGBA_8888_GrPixelConfig;
    254 
    255         fLazyProxy = proxyProvider->createLazyProxy(
    256                 [testExecuteValue, shouldFailInstantiation, desc] (
    257                         GrResourceProvider* rp, GrSurfaceOrigin* /*origin*/) {
    258                     if (!rp) {
    259                         return sk_sp<GrTexture>();
    260                     }
    261                     if (shouldFailInstantiation) {
    262                         *testExecuteValue = 1;
    263                         return sk_sp<GrTexture>();
    264                     }
    265                     return rp->createTexture(desc, SkBudgeted::kNo);
    266                 }, desc, GrMipMapped::kNo, SkBackingFit::kExact, SkBudgeted::kNo);
    267 
    268         this->setBounds(SkRect::MakeIWH(kSize, kSize),
    269                         HasAABloat::kNo, IsZeroArea::kNo);
    270     }
    271 
    272     void visitProxies(const VisitProxyFunc& func) const override {
    273         func(fLazyProxy.get());
    274     }
    275 
    276 private:
    277     const char* name() const override { return "LazyFailedInstantiationTestOp"; }
    278     FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
    279     RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*,
    280                                 GrPixelConfigIsClamped) override {
    281         return RequiresDstTexture::kNo;
    282     }
    283     bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; }
    284     void onPrepare(GrOpFlushState*) override {}
    285     void onExecute(GrOpFlushState* state) override {
    286         *fTestExecuteValue = 2;
    287     }
    288 
    289     int* fTestExecuteValue;
    290     sk_sp<GrSurfaceProxy> fLazyProxy;
    291 
    292     typedef GrDrawOp INHERITED;
    293 };
    294 
    295 // Test that when a lazy proxy fails to instantiate during flush that we drop the Op that it was
    296 // associated with.
    297 DEF_GPUTEST(LazyProxyFailedInstantiationTest, reporter, /* options */) {
    298     GrMockOptions mockOptions;
    299     sk_sp<GrContext> ctx = GrContext::MakeMock(&mockOptions, GrContextOptions());
    300     GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();
    301     for (bool failInstantiation : {false, true}) {
    302         sk_sp<GrRenderTargetContext> rtc =
    303                 ctx->makeDeferredRenderTargetContext(SkBackingFit::kExact, 100, 100,
    304                                                      kRGBA_8888_GrPixelConfig, nullptr);
    305         REPORTER_ASSERT(reporter, rtc);
    306 
    307         rtc->clear(nullptr, 0xbaaaaaad, GrRenderTargetContext::CanClearFullscreen::kYes);
    308 
    309         int executeTestValue = 0;
    310         rtc->priv().testingOnly_addDrawOp(
    311                 skstd::make_unique<LazyFailedInstantiationTestOp>(proxyProvider, &executeTestValue,
    312                                                                   failInstantiation));
    313         ctx->flush();
    314 
    315         if (failInstantiation) {
    316 #ifdef SK_DISABLE_EXPLICIT_GPU_RESOURCE_ALLOCATION
    317             // When we disable explicit gpu resource allocation we don't throw away ops that have
    318             // uninstantiated proxies.
    319             REPORTER_ASSERT(reporter, 2 == executeTestValue);
    320 #else
    321             REPORTER_ASSERT(reporter, 1 == executeTestValue);
    322 #endif
    323         } else {
    324             REPORTER_ASSERT(reporter, 2 == executeTestValue);
    325         }
    326     }
    327 
    328 }
    329 
    330 #endif
    331