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/ganesh/GrBackendSurface.h" 17 #include "include/gpu/ganesh/GrContextOptions.h" 18 #include "include/gpu/ganesh/GrDirectContext.h" 19 #include "include/gpu/ganesh/GrRecordingContext.h" 20 #include "include/gpu/ganesh/GrTypes.h" 21 #include "include/gpu/ganesh/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 defined(GPU_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(), skgpu::Mipmapped::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::ganesh::SurfaceDrawContext *,GrDrawOp *,GrAAType,GrAppliedClip * out,SkRect * bounds) const231 Effect apply(GrRecordingContext* rContext, 232 skgpu::ganesh::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::ganesh::SurfaceDrawContext::Make(ctx.get(), 263 GrColorType::kRGBA_8888, 264 nullptr, 265 SkBackingFit::kExact, 266 {100, 100}, 267 SkSurfaceProps(), 268 /*label=*/{}); 269 REPORTER_ASSERT(reporter, sdc); 270 auto mockAtlas = skgpu::ganesh::SurfaceDrawContext::Make(ctx.get(), 271 GrColorType::kAlpha_F16, 272 nullptr, 273 SkBackingFit::kExact, 274 {10, 10}, 275 SkSurfaceProps(), 276 /*label=*/{}); 277 REPORTER_ASSERT(reporter, mockAtlas); 278 LazyProxyTest::Clip clip(&test, mockAtlas->asTextureProxy()); 279 sdc->addDrawOp(&clip, 280 LazyProxyTest::Op::Make(ctx.get(), proxyProvider, &test, nullTexture)); 281 ctx->priv().testingOnly_flushAndRemoveOnFlushCallbackObject(&test); 282 } 283 } 284 285 static const int kSize = 16; 286 287 DEF_GANESH_TEST(LazyProxyReleaseTest, reporter, /* options */, CtsEnforcement::kApiLevel_T) { 288 GrMockOptions mockOptions; 289 sk_sp<GrDirectContext> ctx = GrDirectContext::MakeMock(&mockOptions, GrContextOptions()); 290 auto proxyProvider = ctx->priv().proxyProvider(); 291 const GrCaps* caps = ctx->priv().caps(); 292 293 GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888, 294 GrRenderable::kNo); 295 296 auto tex = ctx->priv().resourceProvider()->createTexture({kSize, kSize}, 297 format, 298 GrTextureType::k2D, 299 GrRenderable::kNo, 300 1, 301 skgpu::Mipmapped::kNo, 302 skgpu::Budgeted::kNo, 303 GrProtected::kNo, 304 /*label=*/{}); 305 using LazyInstantiationResult = GrSurfaceProxy::LazyCallbackResult; 306 for (bool doInstantiate : {true, false}) { 307 for (bool releaseCallback : {false, true}) { 308 int testCount = 0; 309 // Sets an integer to 1 when the callback is called and -1 when it is deleted. 310 class TestCallback { 311 public: TestCallback(int * value,bool releaseCallback,sk_sp<GrTexture> tex)312 TestCallback(int* value, bool releaseCallback, sk_sp<GrTexture> tex) 313 : fValue(value) 314 , fReleaseCallback(releaseCallback) 315 , fTexture(std::move(tex)) {} TestCallback(const TestCallback & that)316 TestCallback(const TestCallback& that) { SkASSERT(0); } TestCallback(TestCallback && that)317 TestCallback(TestCallback&& that) 318 : fValue(that.fValue) 319 , fReleaseCallback(that.fReleaseCallback) 320 , fTexture(std::move(that.fTexture)) { 321 that.fValue = nullptr; 322 } 323 ~TestCallback()324 ~TestCallback() { fValue ? (void)(*fValue = -1) : void(); } 325 operator =(TestCallback && that)326 TestCallback& operator=(TestCallback&& that) { 327 fValue = std::exchange(that.fValue, nullptr); 328 return *this; 329 } 330 TestCallback& operator=(const TestCallback& that) = delete; 331 operator ()(GrResourceProvider *,const GrSurfaceProxy::LazySurfaceDesc &) const332 LazyInstantiationResult operator()(GrResourceProvider*, 333 const GrSurfaceProxy::LazySurfaceDesc&) const { 334 *fValue = 1; 335 return {fTexture, fReleaseCallback}; 336 } 337 338 private: 339 int* fValue = nullptr; 340 bool fReleaseCallback; 341 sk_sp<GrTexture> fTexture; 342 }; 343 sk_sp<GrTextureProxy> proxy = 344 proxyProvider->createLazyProxy(TestCallback(&testCount, releaseCallback, tex), 345 format, 346 {kSize, kSize}, 347 skgpu::Mipmapped::kNo, 348 GrMipmapStatus::kNotAllocated, 349 GrInternalSurfaceFlags::kNone, 350 SkBackingFit::kExact, 351 skgpu::Budgeted::kNo, 352 GrProtected::kNo, 353 GrSurfaceProxy::UseAllocator::kYes, 354 /*label=*/{}); 355 356 REPORTER_ASSERT(reporter, proxy.get()); 357 REPORTER_ASSERT(reporter, 0 == testCount); 358 359 if (doInstantiate) { 360 proxy->priv().doLazyInstantiation(ctx->priv().resourceProvider()); 361 if (releaseCallback) { 362 // We will call the cleanup and delete the callback in the 363 // doLazyInstantiationCall. 364 REPORTER_ASSERT(reporter, -1 == testCount); 365 } else { 366 REPORTER_ASSERT(reporter, 1 == testCount); 367 } 368 proxy.reset(); 369 REPORTER_ASSERT(reporter, -1 == testCount); 370 } else { 371 proxy.reset(); 372 REPORTER_ASSERT(reporter, -1 == testCount); 373 } 374 } 375 } 376 } 377 378 class LazyFailedInstantiationTestOp : public GrDrawOp { 379 public: 380 DEFINE_OP_CLASS_ID 381 Make(GrRecordingContext * rContext,GrProxyProvider * proxyProvider,int * testExecuteValue,bool shouldFailInstantiation)382 static GrOp::Owner Make(GrRecordingContext* rContext, 383 GrProxyProvider* proxyProvider, 384 int* testExecuteValue, 385 bool shouldFailInstantiation) { 386 return GrOp::Make<LazyFailedInstantiationTestOp>(rContext, 387 rContext->priv().caps(), 388 proxyProvider, 389 testExecuteValue, 390 shouldFailInstantiation); 391 } 392 visitProxies(const GrVisitProxyFunc & func) const393 void visitProxies(const GrVisitProxyFunc& func) const override { 394 func(fLazyProxy.get(), skgpu::Mipmapped::kNo); 395 } 396 397 private: 398 friend class GrOp; // for ctor 399 LazyFailedInstantiationTestOp(const GrCaps * caps,GrProxyProvider * proxyProvider,int * testExecuteValue,bool shouldFailInstantiation)400 LazyFailedInstantiationTestOp(const GrCaps* caps, GrProxyProvider* proxyProvider, 401 int* testExecuteValue, bool shouldFailInstantiation) 402 : INHERITED(ClassID()) 403 , fTestExecuteValue(testExecuteValue) { 404 SkISize dims = {kSize, kSize}; 405 GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888, 406 GrRenderable::kNo); 407 408 fLazyProxy = proxyProvider->createLazyProxy( 409 [testExecuteValue, shouldFailInstantiation]( 410 GrResourceProvider* rp, const GrSurfaceProxy::LazySurfaceDesc& desc) 411 -> GrSurfaceProxy::LazyCallbackResult { 412 if (shouldFailInstantiation) { 413 *testExecuteValue = 1; 414 return {}; 415 } 416 return {rp->createTexture(desc.fDimensions, 417 desc.fFormat, 418 desc.fTextureType, 419 desc.fRenderable, 420 desc.fSampleCnt, 421 desc.fMipmapped, 422 desc.fBudgeted, 423 desc.fProtected, 424 /*label=*/{}), 425 true, GrSurfaceProxy::LazyInstantiationKeyMode::kUnsynced}; 426 }, 427 format, 428 dims, 429 skgpu::Mipmapped::kNo, 430 GrMipmapStatus::kNotAllocated, 431 GrInternalSurfaceFlags::kNone, 432 SkBackingFit::kExact, 433 skgpu::Budgeted::kNo, 434 GrProtected::kNo, 435 GrSurfaceProxy::UseAllocator::kYes, 436 /*label=*/{}); 437 438 SkASSERT(fLazyProxy.get()); 439 440 this->setBounds(SkRect::Make(dims), HasAABloat::kNo, IsHairline::kNo); 441 } 442 name() const443 const char* name() const override { return "LazyFailedInstantiationTestOp"; } fixedFunctionFlags() const444 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; } finalize(const GrCaps &,const GrAppliedClip *,GrClampType)445 GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override { 446 return GrProcessorSet::EmptySetAnalysis(); 447 } onPrePrepare(GrRecordingContext *,const GrSurfaceProxyView & writeView,GrAppliedClip *,const GrDstProxyView &,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)448 void onPrePrepare(GrRecordingContext*, 449 const GrSurfaceProxyView& writeView, 450 GrAppliedClip*, 451 const GrDstProxyView&, 452 GrXferBarrierFlags renderPassXferBarriers, 453 GrLoadOp colorLoadOp) override {} onPrepare(GrOpFlushState *)454 void onPrepare(GrOpFlushState*) override {} onExecute(GrOpFlushState * state,const SkRect & chainBounds)455 void onExecute(GrOpFlushState* state, const SkRect& chainBounds) override { 456 *fTestExecuteValue = 2; 457 } 458 459 int* fTestExecuteValue; 460 sk_sp<GrTextureProxy> fLazyProxy; 461 462 using INHERITED = GrDrawOp; 463 }; 464 465 // Test that when a lazy proxy fails to instantiate during flush that we drop the Op that it was 466 // associated with. 467 DEF_GANESH_TEST(LazyProxyFailedInstantiationTest, 468 reporter, 469 /* options */, 470 CtsEnforcement::kApiLevel_T) { 471 GrMockOptions mockOptions; 472 sk_sp<GrDirectContext> ctx = GrDirectContext::MakeMock(&mockOptions, GrContextOptions()); 473 GrProxyProvider* proxyProvider = ctx->priv().proxyProvider(); 474 for (bool failInstantiation : {false, true}) { 475 auto sdc = skgpu::ganesh::SurfaceDrawContext::Make(ctx.get(), 476 GrColorType::kRGBA_8888, 477 nullptr, 478 SkBackingFit::kExact, 479 {100, 100}, 480 SkSurfaceProps(), 481 /*label=*/{}); 482 REPORTER_ASSERT(reporter, sdc); 483 484 sdc->clear(SkPMColor4f::FromBytes_RGBA(0xbaaaaaad)); 485 486 int executeTestValue = 0; 487 sdc->addDrawOp(LazyFailedInstantiationTestOp::Make(ctx.get(), proxyProvider, 488 &executeTestValue, failInstantiation)); 489 ctx->flushAndSubmit(); 490 491 if (failInstantiation) { 492 REPORTER_ASSERT(reporter, 1 == executeTestValue); 493 } else { 494 REPORTER_ASSERT(reporter, 2 == executeTestValue); 495 } 496 } 497 } 498