• 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 "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:
LazyProxyTest(skiatest::Reporter * reporter)32     LazyProxyTest(skiatest::Reporter* reporter)
33             : fReporter(reporter)
34             , fHasOpTexture(false)
35             , fHasClipTexture(false) {
36     }
37 
~LazyProxyTest()38     ~LazyProxyTest() override {
39         REPORTER_ASSERT(fReporter, fHasOpTexture);
40         REPORTER_ASSERT(fReporter, fHasClipTexture);
41     }
42 
preFlush(GrOnFlushResourceProvider *,const uint32_t *,int,SkTArray<sk_sp<GrRenderTargetContext>> *)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 
postFlush(GrDeferredUploadToken,const uint32_t * opListIDs,int numOpListIDs)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 
Op(GrProxyProvider * proxyProvider,LazyProxyTest * test,bool nullTexture)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 
visitProxies(const VisitProxyFunc & func) const83         void visitProxies(const VisitProxyFunc& func) const override {
84             func(fProxy.get());
85         }
86 
onExecute(GrOpFlushState *)87         void onExecute(GrOpFlushState*) override {
88             REPORTER_ASSERT(fTest->fReporter, fTest->fHasOpTexture);
89             REPORTER_ASSERT(fTest->fReporter, fTest->fHasClipTexture);
90         }
91 
92     private:
name() const93         const char* name() const override { return "LazyProxyTest::Op"; }
fixedFunctionFlags() const94         FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
finalize(const GrCaps &,const GrAppliedClip *,GrPixelConfigIsClamped)95         RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*,
96                                     GrPixelConfigIsClamped) override {
97             return RequiresDstTexture::kNo;
98         }
wasRecorded(GrRenderTargetOpList *)99         void wasRecorded(GrRenderTargetOpList*) override {}
onCombineIfPossible(GrOp * other,const GrCaps & caps)100         bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; }
onPrepare(GrOpFlushState *)101         void onPrepare(GrOpFlushState*) override {}
102 
103         LazyProxyTest* const fTest;
104         sk_sp<GrTextureProxy> fProxy;
105     };
106 
107     class ClipFP : public GrFragmentProcessor {
108     public:
ClipFP(GrProxyProvider * proxyProvider,LazyProxyTest * test,GrTextureProxy * atlas)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:
name() const133         const char* name() const override { return "LazyProxyTest::ClipFP"; }
clone() const134         std::unique_ptr<GrFragmentProcessor> clone() const override {
135             return skstd::make_unique<ClipFP>(fProxyProvider, fTest, fAtlas);
136         }
onCreateGLSLInstance() const137         GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return nullptr; }
onGetGLSLProcessorKey(const GrShaderCaps &,GrProcessorKeyBuilder *) const138         void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
onIsEqual(const GrFragmentProcessor &) const139         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:
Clip(LazyProxyTest * test,GrTextureProxy * atlas)151         Clip(LazyProxyTest* test, GrTextureProxy* atlas)
152                 : fTest(test)
153                 , fAtlas(atlas) {}
154 
155     private:
apply(GrContext * context,GrRenderTargetContext *,bool,bool,GrAppliedClip * out,SkRect * bounds) const156         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         }
quickContains(const SkRect &) const162         bool quickContains(const SkRect&) const final { return false; }
isRRect(const SkRect & rtBounds,SkRRect * rr,GrAA *) const163         bool isRRect(const SkRect& rtBounds, SkRRect* rr, GrAA*) const final { return false; }
getConservativeBounds(int width,int height,SkIRect * rect,bool * iior) const164         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(
__anona8e77fba0302(GrResourceProvider* resourceProvider) 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 
LazyFailedInstantiationTestOp(GrProxyProvider * proxyProvider,int * testExecuteValue,bool shouldFailInstantiation)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 
visitProxies(const VisitProxyFunc & func) const285     void visitProxies(const VisitProxyFunc& func) const override {
286         func(fLazyProxy.get());
287     }
288 
289 private:
name() const290     const char* name() const override { return "LazyFailedInstantiationTestOp"; }
fixedFunctionFlags() const291     FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
finalize(const GrCaps &,const GrAppliedClip *,GrPixelConfigIsClamped)292     RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*,
293                                 GrPixelConfigIsClamped) override {
294         return RequiresDstTexture::kNo;
295     }
onCombineIfPossible(GrOp * other,const GrCaps & caps)296     bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; }
onPrepare(GrOpFlushState *)297     void onPrepare(GrOpFlushState*) override {}
onExecute(GrOpFlushState * state)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