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