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