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 "include/core/SkAlphaType.h" 9 #include "include/core/SkColorSpace.h" 10 #include "include/core/SkRect.h" 11 #include "include/core/SkRefCnt.h" 12 #include "include/core/SkSize.h" 13 #include "include/core/SkSurfaceProps.h" 14 #include "include/core/SkTypes.h" 15 #include "include/gpu/GpuTypes.h" 16 #include "include/gpu/GrBackendSurface.h" 17 #include "include/gpu/GrContextOptions.h" 18 #include "include/gpu/GrDirectContext.h" 19 #include "include/gpu/GrRecordingContext.h" 20 #include "include/gpu/GrTypes.h" 21 #include "include/gpu/mock/GrMockTypes.h" 22 #include "include/private/SkColorData.h" 23 #include "include/private/gpu/ganesh/GrTypesPriv.h" 24 #include "src/core/SkRectPriv.h" 25 #include "src/gpu/AtlasTypes.h" 26 #include "src/gpu/SkBackingFit.h" 27 #include "src/gpu/Swizzle.h" 28 #include "src/gpu/ganesh/GrAppliedClip.h" 29 #include "src/gpu/ganesh/GrCaps.h" 30 #include "src/gpu/ganesh/GrClip.h" 31 #include "src/gpu/ganesh/GrDirectContextPriv.h" 32 #include "src/gpu/ganesh/GrFragmentProcessor.h" 33 #include "src/gpu/ganesh/GrOnFlushResourceProvider.h" 34 #include "src/gpu/ganesh/GrProcessorSet.h" 35 #include "src/gpu/ganesh/GrProxyProvider.h" 36 #include "src/gpu/ganesh/GrRecordingContextPriv.h" 37 #include "src/gpu/ganesh/GrResourceProvider.h" 38 #include "src/gpu/ganesh/GrSurface.h" 39 #include "src/gpu/ganesh/GrSurfaceProxy.h" 40 #include "src/gpu/ganesh/GrSurfaceProxyPriv.h" 41 #include "src/gpu/ganesh/GrTexture.h" 42 #include "src/gpu/ganesh/GrTextureProxy.h" 43 #include "src/gpu/ganesh/SurfaceDrawContext.h" 44 #include "src/gpu/ganesh/effects/GrTextureEffect.h" 45 #include "src/gpu/ganesh/ops/GrDrawOp.h" 46 #include "src/gpu/ganesh/ops/GrOp.h" 47 #include "tests/CtsEnforcement.h" 48 #include "tests/Test.h" 49 50 #include <functional> 51 #include <initializer_list> 52 #include <memory> 53 #include <utility> 54 55 class GrDstProxyView; 56 class GrOpFlushState; 57 class GrSurfaceProxyView; 58 enum class GrXferBarrierFlags; 59 namespace skgpu { class KeyBuilder; } 60 struct GrShaderCaps; 61 62 // This test verifies that lazy proxy callbacks get invoked during flush, after onFlush callbacks, 63 // but before Ops are executed. It also ensures that lazy proxy callbacks are invoked both for 64 // regular Ops and for clips. 65 class LazyProxyTest final : public GrOnFlushCallbackObject { 66 public: LazyProxyTest(skiatest::Reporter * reporter)67 LazyProxyTest(skiatest::Reporter* reporter) 68 : fReporter(reporter) 69 , fHasOpTexture(false) 70 , fHasClipTexture(false) { 71 } 72 ~LazyProxyTest()73 ~LazyProxyTest() override { 74 REPORTER_ASSERT(fReporter, fHasOpTexture); 75 REPORTER_ASSERT(fReporter, fHasClipTexture); 76 } 77 preFlush(GrOnFlushResourceProvider * onFlushRP)78 bool preFlush(GrOnFlushResourceProvider* onFlushRP) override { 79 #if GR_TEST_UTILS 80 if (onFlushRP->failFlushTimeCallbacks()) { 81 return false; 82 } 83 #endif 84 85 REPORTER_ASSERT(fReporter, !fHasOpTexture); 86 REPORTER_ASSERT(fReporter, !fHasClipTexture); 87 return true; 88 } 89 postFlush(skgpu::AtlasToken)90 void postFlush(skgpu::AtlasToken) override { 91 REPORTER_ASSERT(fReporter, fHasOpTexture); 92 REPORTER_ASSERT(fReporter, fHasClipTexture); 93 } 94 95 class Op final : public GrDrawOp { 96 public: 97 DEFINE_OP_CLASS_ID 98 Make(GrRecordingContext * context,GrProxyProvider * proxyProvider,LazyProxyTest * test,bool nullTexture)99 static GrOp::Owner Make(GrRecordingContext* context, 100 GrProxyProvider* proxyProvider, 101 LazyProxyTest* test, 102 bool nullTexture) { 103 return GrOp::Make<Op>(context, context, proxyProvider, test, nullTexture); 104 } 105 visitProxies(const GrVisitProxyFunc & func) const106 void visitProxies(const GrVisitProxyFunc& func) const override { 107 func(fProxy.get(), GrMipmapped::kNo); 108 } 109 onExecute(GrOpFlushState *,const SkRect & chainBounds)110 void onExecute(GrOpFlushState*, const SkRect& chainBounds) override { 111 REPORTER_ASSERT(fTest->fReporter, fTest->fHasOpTexture); 112 REPORTER_ASSERT(fTest->fReporter, fTest->fHasClipTexture); 113 } 114 115 private: 116 friend class GrOp; // for ctor 117 Op(GrRecordingContext * ctx,GrProxyProvider * proxyProvider,LazyProxyTest * test,bool nullTexture)118 Op(GrRecordingContext* ctx, GrProxyProvider* proxyProvider, 119 LazyProxyTest* test, bool nullTexture) 120 : GrDrawOp(ClassID()), fTest(test) { 121 const GrBackendFormat format = 122 ctx->priv().caps()->getDefaultBackendFormat(GrColorType::kBGR_565, 123 GrRenderable::kNo); 124 fProxy = GrProxyProvider::MakeFullyLazyProxy( 125 [this, nullTexture](GrResourceProvider* rp, 126 const GrSurfaceProxy::LazySurfaceDesc& desc) 127 -> GrSurfaceProxy::LazyCallbackResult { 128 REPORTER_ASSERT(fTest->fReporter, !fTest->fHasOpTexture); 129 fTest->fHasOpTexture = true; 130 if (nullTexture) { 131 return {}; 132 } else { 133 static constexpr SkISize kDimensions = {1234, 567}; 134 sk_sp<GrTexture> texture = rp->createTexture(kDimensions, 135 desc.fFormat, 136 desc.fTextureType, 137 desc.fRenderable, 138 desc.fSampleCnt, 139 desc.fMipmapped, 140 desc.fBudgeted, 141 desc.fProtected, 142 /*label=*/{}); 143 REPORTER_ASSERT(fTest->fReporter, texture); 144 return texture; 145 } 146 }, 147 format, GrRenderable::kNo, 1, GrProtected::kNo, *proxyProvider->caps(), 148 GrSurfaceProxy::UseAllocator::kYes); 149 150 this->setBounds(SkRectPriv::MakeLargest(), GrOp::HasAABloat::kNo, 151 GrOp::IsHairline::kNo); 152 } 153 name() const154 const char* name() const override { return "LazyProxyTest::Op"; } fixedFunctionFlags() const155 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; } finalize(const GrCaps &,const GrAppliedClip * clip,GrClampType)156 GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip* clip, 157 GrClampType) override { 158 return GrProcessorSet::EmptySetAnalysis(); 159 } onPrePrepare(GrRecordingContext *,const GrSurfaceProxyView & writeView,GrAppliedClip *,const GrDstProxyView &,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)160 void onPrePrepare(GrRecordingContext*, 161 const GrSurfaceProxyView& writeView, 162 GrAppliedClip*, 163 const GrDstProxyView&, 164 GrXferBarrierFlags renderPassXferBarriers, 165 GrLoadOp colorLoadOp) override {} 166 onPrepare(GrOpFlushState *)167 void onPrepare(GrOpFlushState*) override {} 168 169 LazyProxyTest* const fTest; 170 sk_sp<GrTextureProxy> fProxy; 171 }; 172 173 class ClipFP : public GrFragmentProcessor { 174 public: ClipFP(GrRecordingContext * ctx,GrProxyProvider * proxyProvider,LazyProxyTest * test,GrTextureProxy * atlas)175 ClipFP(GrRecordingContext* ctx, GrProxyProvider* proxyProvider, LazyProxyTest* test, 176 GrTextureProxy* atlas) 177 : GrFragmentProcessor(kTestFP_ClassID, kNone_OptimizationFlags) 178 , fContext(ctx) 179 , fProxyProvider(proxyProvider) 180 , fTest(test) 181 , fAtlas(atlas) { 182 static const GrColorType kColorType = GrColorType::kAlpha_F16; 183 static const GrSurfaceOrigin kOrigin = kBottomLeft_GrSurfaceOrigin; 184 const GrBackendFormat format = 185 ctx->priv().caps()->getDefaultBackendFormat(kColorType, GrRenderable::kYes); 186 skgpu::Swizzle readSwizzle = ctx->priv().caps()->getReadSwizzle(format, kColorType); 187 fLazyProxy = GrProxyProvider::MakeFullyLazyProxy( 188 [this](GrResourceProvider* rp, const GrSurfaceProxy::LazySurfaceDesc&) 189 -> GrSurfaceProxy::LazyCallbackResult { 190 REPORTER_ASSERT(fTest->fReporter, !fTest->fHasClipTexture); 191 fTest->fHasClipTexture = true; 192 fAtlas->instantiate(rp); 193 return sk_ref_sp(fAtlas->peekTexture()); 194 }, 195 format, GrRenderable::kYes, 1, GrProtected::kNo, *proxyProvider->caps(), 196 GrSurfaceProxy::UseAllocator::kYes); 197 auto atlasEffect = GrTextureEffect::Make({fLazyProxy, kOrigin, readSwizzle}, 198 kPremul_SkAlphaType); 199 this->registerChild(std::move(atlasEffect)); 200 } 201 202 private: name() const203 const char* name() const override { return "LazyProxyTest::ClipFP"; } clone() const204 std::unique_ptr<GrFragmentProcessor> clone() const override { 205 return std::make_unique<ClipFP>(fContext, fProxyProvider, fTest, fAtlas); 206 } onMakeProgramImpl() const207 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override { 208 return nullptr; 209 } onAddToKey(const GrShaderCaps &,skgpu::KeyBuilder *) const210 void onAddToKey(const GrShaderCaps&, skgpu::KeyBuilder*) const override {} onIsEqual(const GrFragmentProcessor &) const211 bool onIsEqual(const GrFragmentProcessor&) const override { return false; } 212 213 GrRecordingContext* const fContext; 214 GrProxyProvider* const fProxyProvider; 215 LazyProxyTest* const fTest; 216 GrTextureProxy* const fAtlas; 217 sk_sp<GrTextureProxy> fLazyProxy; 218 }; 219 220 221 class Clip : public GrClip { 222 public: Clip(LazyProxyTest * test,GrTextureProxy * atlas)223 Clip(LazyProxyTest* test, GrTextureProxy* atlas) 224 : fTest(test) 225 , fAtlas(atlas) {} 226 227 private: getConservativeBounds() const228 SkIRect getConservativeBounds() const final { 229 return SkIRect::MakeSize(fAtlas->dimensions()); 230 } apply(GrRecordingContext * rContext,skgpu::v1::SurfaceDrawContext *,GrDrawOp *,GrAAType,GrAppliedClip * out,SkRect * bounds) const231 Effect apply(GrRecordingContext* rContext, 232 skgpu::v1::SurfaceDrawContext*, 233 GrDrawOp*, 234 GrAAType, 235 GrAppliedClip* out, 236 SkRect* bounds) const override { 237 GrProxyProvider* proxyProvider = rContext->priv().proxyProvider(); 238 out->addCoverageFP(std::make_unique<ClipFP>(rContext, proxyProvider, fTest, fAtlas)); 239 return Effect::kClipped; 240 } 241 242 LazyProxyTest* const fTest; 243 GrTextureProxy* fAtlas; 244 }; 245 246 private: 247 skiatest::Reporter* fReporter; 248 bool fHasOpTexture; 249 bool fHasClipTexture; 250 }; 251 252 DEF_GANESH_TEST(LazyProxyTest, reporter, /* options */, CtsEnforcement::kApiLevel_T) { 253 GrMockOptions mockOptions; 254 mockOptions.fConfigOptions[(int)GrColorType::kAlpha_F16].fRenderability = 255 GrMockOptions::ConfigOptions::Renderability::kNonMSAA; 256 mockOptions.fConfigOptions[(int)GrColorType::kAlpha_F16].fTexturable = true; 257 sk_sp<GrDirectContext> ctx = GrDirectContext::MakeMock(&mockOptions, GrContextOptions()); 258 GrProxyProvider* proxyProvider = ctx->priv().proxyProvider(); 259 for (bool nullTexture : {false, true}) { 260 LazyProxyTest test(reporter); 261 ctx->priv().addOnFlushCallbackObject(&test); 262 auto sdc = skgpu::v1::SurfaceDrawContext::Make(ctx.get(), GrColorType::kRGBA_8888, nullptr, 263 SkBackingFit::kExact, {100, 100}, 264 SkSurfaceProps(), /*label=*/{}); 265 REPORTER_ASSERT(reporter, sdc); 266 auto mockAtlas = skgpu::v1::SurfaceDrawContext::Make(ctx.get(), GrColorType::kAlpha_F16, 267 nullptr, SkBackingFit::kExact, 268 {10, 10}, SkSurfaceProps(), 269 /*label=*/{}); 270 REPORTER_ASSERT(reporter, mockAtlas); 271 LazyProxyTest::Clip clip(&test, mockAtlas->asTextureProxy()); 272 sdc->addDrawOp(&clip, 273 LazyProxyTest::Op::Make(ctx.get(), proxyProvider, &test, nullTexture)); 274 ctx->priv().testingOnly_flushAndRemoveOnFlushCallbackObject(&test); 275 } 276 } 277 278 static const int kSize = 16; 279 280 DEF_GANESH_TEST(LazyProxyReleaseTest, reporter, /* options */, CtsEnforcement::kApiLevel_T) { 281 GrMockOptions mockOptions; 282 sk_sp<GrDirectContext> ctx = GrDirectContext::MakeMock(&mockOptions, GrContextOptions()); 283 auto proxyProvider = ctx->priv().proxyProvider(); 284 const GrCaps* caps = ctx->priv().caps(); 285 286 GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888, 287 GrRenderable::kNo); 288 289 auto tex = ctx->priv().resourceProvider()->createTexture({kSize, kSize}, 290 format, 291 GrTextureType::k2D, 292 GrRenderable::kNo, 293 1, 294 GrMipmapped::kNo, 295 skgpu::Budgeted::kNo, 296 GrProtected::kNo, 297 /*label=*/{}); 298 using LazyInstantiationResult = GrSurfaceProxy::LazyCallbackResult; 299 for (bool doInstantiate : {true, false}) { 300 for (bool releaseCallback : {false, true}) { 301 int testCount = 0; 302 // Sets an integer to 1 when the callback is called and -1 when it is deleted. 303 class TestCallback { 304 public: TestCallback(int * value,bool releaseCallback,sk_sp<GrTexture> tex)305 TestCallback(int* value, bool releaseCallback, sk_sp<GrTexture> tex) 306 : fValue(value) 307 , fReleaseCallback(releaseCallback) 308 , fTexture(std::move(tex)) {} TestCallback(const TestCallback & that)309 TestCallback(const TestCallback& that) { SkASSERT(0); } TestCallback(TestCallback && that)310 TestCallback(TestCallback&& that) 311 : fValue(that.fValue) 312 , fReleaseCallback(that.fReleaseCallback) 313 , fTexture(std::move(that.fTexture)) { 314 that.fValue = nullptr; 315 } 316 ~TestCallback()317 ~TestCallback() { fValue ? (void)(*fValue = -1) : void(); } 318 operator =(TestCallback && that)319 TestCallback& operator=(TestCallback&& that) { 320 fValue = std::exchange(that.fValue, nullptr); 321 return *this; 322 } 323 TestCallback& operator=(const TestCallback& that) = delete; 324 operator ()(GrResourceProvider *,const GrSurfaceProxy::LazySurfaceDesc &) const325 LazyInstantiationResult operator()(GrResourceProvider*, 326 const GrSurfaceProxy::LazySurfaceDesc&) const { 327 *fValue = 1; 328 return {fTexture, fReleaseCallback}; 329 } 330 331 private: 332 int* fValue = nullptr; 333 bool fReleaseCallback; 334 sk_sp<GrTexture> fTexture; 335 }; 336 sk_sp<GrTextureProxy> proxy = 337 proxyProvider->createLazyProxy(TestCallback(&testCount, releaseCallback, tex), 338 format, 339 {kSize, kSize}, 340 GrMipmapped::kNo, 341 GrMipmapStatus::kNotAllocated, 342 GrInternalSurfaceFlags::kNone, 343 SkBackingFit::kExact, 344 skgpu::Budgeted::kNo, 345 GrProtected::kNo, 346 GrSurfaceProxy::UseAllocator::kYes, 347 /*label=*/{}); 348 349 REPORTER_ASSERT(reporter, proxy.get()); 350 REPORTER_ASSERT(reporter, 0 == testCount); 351 352 if (doInstantiate) { 353 proxy->priv().doLazyInstantiation(ctx->priv().resourceProvider()); 354 if (releaseCallback) { 355 // We will call the cleanup and delete the callback in the 356 // doLazyInstantiationCall. 357 REPORTER_ASSERT(reporter, -1 == testCount); 358 } else { 359 REPORTER_ASSERT(reporter, 1 == testCount); 360 } 361 proxy.reset(); 362 REPORTER_ASSERT(reporter, -1 == testCount); 363 } else { 364 proxy.reset(); 365 REPORTER_ASSERT(reporter, -1 == testCount); 366 } 367 } 368 } 369 } 370 371 class LazyFailedInstantiationTestOp : public GrDrawOp { 372 public: 373 DEFINE_OP_CLASS_ID 374 Make(GrRecordingContext * rContext,GrProxyProvider * proxyProvider,int * testExecuteValue,bool shouldFailInstantiation)375 static GrOp::Owner Make(GrRecordingContext* rContext, 376 GrProxyProvider* proxyProvider, 377 int* testExecuteValue, 378 bool shouldFailInstantiation) { 379 return GrOp::Make<LazyFailedInstantiationTestOp>(rContext, 380 rContext->priv().caps(), 381 proxyProvider, 382 testExecuteValue, 383 shouldFailInstantiation); 384 } 385 visitProxies(const GrVisitProxyFunc & func) const386 void visitProxies(const GrVisitProxyFunc& func) const override { 387 func(fLazyProxy.get(), GrMipmapped::kNo); 388 } 389 390 private: 391 friend class GrOp; // for ctor 392 LazyFailedInstantiationTestOp(const GrCaps * caps,GrProxyProvider * proxyProvider,int * testExecuteValue,bool shouldFailInstantiation)393 LazyFailedInstantiationTestOp(const GrCaps* caps, GrProxyProvider* proxyProvider, 394 int* testExecuteValue, bool shouldFailInstantiation) 395 : INHERITED(ClassID()) 396 , fTestExecuteValue(testExecuteValue) { 397 SkISize dims = {kSize, kSize}; 398 GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888, 399 GrRenderable::kNo); 400 401 fLazyProxy = proxyProvider->createLazyProxy( 402 [testExecuteValue, shouldFailInstantiation]( 403 GrResourceProvider* rp, const GrSurfaceProxy::LazySurfaceDesc& desc) 404 -> GrSurfaceProxy::LazyCallbackResult { 405 if (shouldFailInstantiation) { 406 *testExecuteValue = 1; 407 return {}; 408 } 409 return {rp->createTexture(desc.fDimensions, 410 desc.fFormat, 411 desc.fTextureType, 412 desc.fRenderable, 413 desc.fSampleCnt, 414 desc.fMipmapped, 415 desc.fBudgeted, 416 desc.fProtected, 417 /*label=*/{}), 418 true, GrSurfaceProxy::LazyInstantiationKeyMode::kUnsynced}; 419 }, 420 format, 421 dims, 422 GrMipmapped::kNo, 423 GrMipmapStatus::kNotAllocated, 424 GrInternalSurfaceFlags::kNone, 425 SkBackingFit::kExact, 426 skgpu::Budgeted::kNo, 427 GrProtected::kNo, 428 GrSurfaceProxy::UseAllocator::kYes, 429 /*label=*/{}); 430 431 SkASSERT(fLazyProxy.get()); 432 433 this->setBounds(SkRect::Make(dims), HasAABloat::kNo, IsHairline::kNo); 434 } 435 name() const436 const char* name() const override { return "LazyFailedInstantiationTestOp"; } fixedFunctionFlags() const437 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; } finalize(const GrCaps &,const GrAppliedClip *,GrClampType)438 GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override { 439 return GrProcessorSet::EmptySetAnalysis(); 440 } onPrePrepare(GrRecordingContext *,const GrSurfaceProxyView & writeView,GrAppliedClip *,const GrDstProxyView &,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)441 void onPrePrepare(GrRecordingContext*, 442 const GrSurfaceProxyView& writeView, 443 GrAppliedClip*, 444 const GrDstProxyView&, 445 GrXferBarrierFlags renderPassXferBarriers, 446 GrLoadOp colorLoadOp) override {} onPrepare(GrOpFlushState *)447 void onPrepare(GrOpFlushState*) override {} onExecute(GrOpFlushState * state,const SkRect & chainBounds)448 void onExecute(GrOpFlushState* state, const SkRect& chainBounds) override { 449 *fTestExecuteValue = 2; 450 } 451 452 int* fTestExecuteValue; 453 sk_sp<GrTextureProxy> fLazyProxy; 454 455 using INHERITED = GrDrawOp; 456 }; 457 458 // Test that when a lazy proxy fails to instantiate during flush that we drop the Op that it was 459 // associated with. 460 DEF_GANESH_TEST(LazyProxyFailedInstantiationTest, 461 reporter, 462 /* options */, 463 CtsEnforcement::kApiLevel_T) { 464 GrMockOptions mockOptions; 465 sk_sp<GrDirectContext> ctx = GrDirectContext::MakeMock(&mockOptions, GrContextOptions()); 466 GrProxyProvider* proxyProvider = ctx->priv().proxyProvider(); 467 for (bool failInstantiation : {false, true}) { 468 auto sdc = skgpu::v1::SurfaceDrawContext::Make(ctx.get(), GrColorType::kRGBA_8888, nullptr, 469 SkBackingFit::kExact, {100, 100}, 470 SkSurfaceProps(), /*label=*/{}); 471 REPORTER_ASSERT(reporter, sdc); 472 473 sdc->clear(SkPMColor4f::FromBytes_RGBA(0xbaaaaaad)); 474 475 int executeTestValue = 0; 476 sdc->addDrawOp(LazyFailedInstantiationTestOp::Make(ctx.get(), proxyProvider, 477 &executeTestValue, failInstantiation)); 478 ctx->flushAndSubmit(); 479 480 if (failInstantiation) { 481 REPORTER_ASSERT(reporter, 1 == executeTestValue); 482 } else { 483 REPORTER_ASSERT(reporter, 2 == executeTestValue); 484 } 485 } 486 } 487