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. 30class LazyProxyTest final : public GrOnFlushCallbackObject { 31public: 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, GrSurfaceOrigin* origin) { 62 if (!rp) { 63 return sk_sp<GrTexture>(); 64 } 65 REPORTER_ASSERT(fTest->fReporter, !fTest->fHasOpTexture); 66 fTest->fHasOpTexture = true; 67 *origin = kTopLeft_GrSurfaceOrigin; 68 if (nullTexture) { 69 return sk_sp<GrTexture>(); 70 } else { 71 GrSurfaceDesc desc; 72 desc.fWidth = 1234; 73 desc.fHeight = 567; 74 desc.fOrigin = kTopLeft_GrSurfaceOrigin; 75 desc.fConfig = kRGB_565_GrPixelConfig; 76 sk_sp<GrTexture> texture = rp->createTexture(desc, SkBudgeted::kYes); 77 REPORTER_ASSERT(fTest->fReporter, texture); 78 return texture; 79 } 80 }, GrProxyProvider::Renderable::kNo, kRGB_565_GrPixelConfig); 81 this->setBounds(SkRectPriv::MakeLargest(), GrOp::HasAABloat::kNo, GrOp::IsZeroArea::kNo); 82 } 83 84 void visitProxies(const VisitProxyFunc& func) const override { 85 func(fProxy.get()); 86 } 87 88 void onExecute(GrOpFlushState*) override { 89 REPORTER_ASSERT(fTest->fReporter, fTest->fHasOpTexture); 90 REPORTER_ASSERT(fTest->fReporter, fTest->fHasClipTexture); 91 } 92 93 private: 94 const char* name() const override { return "LazyProxyTest::Op"; } 95 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; } 96 RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*, 97 GrPixelConfigIsClamped) override { 98 return RequiresDstTexture::kNo; 99 } 100 void wasRecorded(GrRenderTargetOpList*) override {} 101 bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; } 102 void onPrepare(GrOpFlushState*) override {} 103 104 LazyProxyTest* const fTest; 105 sk_sp<GrTextureProxy> fProxy; 106 }; 107 108 class ClipFP : public GrFragmentProcessor { 109 public: 110 ClipFP(GrProxyProvider* proxyProvider, LazyProxyTest* test, GrTextureProxy* atlas) 111 : GrFragmentProcessor(kTestFP_ClassID, kNone_OptimizationFlags) 112 , fProxyProvider(proxyProvider) 113 , fTest(test) 114 , fAtlas(atlas) { 115 fLazyProxy = proxyProvider->createFullyLazyProxy([this](GrResourceProvider* rp, 116 GrSurfaceOrigin* origin) { 117 if (!rp) { 118 return sk_sp<GrTexture>(); 119 } 120 REPORTER_ASSERT(fTest->fReporter, !fTest->fHasClipTexture); 121 fTest->fHasClipTexture = true; 122 *origin = kBottomLeft_GrSurfaceOrigin; 123 fAtlas->instantiate(rp); 124 return sk_ref_sp(fAtlas->priv().peekTexture()); 125 }, GrProxyProvider::Renderable::kYes, kAlpha_half_GrPixelConfig); 126 fAccess.reset(fLazyProxy, GrSamplerState::Filter::kNearest, 127 GrSamplerState::WrapMode::kClamp, kFragment_GrShaderFlag); 128 this->addTextureSampler(&fAccess); 129 } 130 131 private: 132 const char* name() const override { return "LazyProxyTest::ClipFP"; } 133 std::unique_ptr<GrFragmentProcessor> clone() const override { 134 return skstd::make_unique<ClipFP>(fProxyProvider, fTest, fAtlas); 135 } 136 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return nullptr; } 137 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {} 138 bool onIsEqual(const GrFragmentProcessor&) const override { return false; } 139 140 GrProxyProvider* const fProxyProvider; 141 LazyProxyTest* const fTest; 142 GrTextureProxy* const fAtlas; 143 sk_sp<GrTextureProxy> fLazyProxy; 144 TextureSampler fAccess; 145 }; 146 147 148 class Clip : public GrClip { 149 public: 150 Clip(LazyProxyTest* test, GrTextureProxy* atlas) 151 : fTest(test) 152 , fAtlas(atlas) {} 153 154 private: 155 bool apply(GrContext* context, GrRenderTargetContext*, bool, bool, GrAppliedClip* out, 156 SkRect* bounds) const override { 157 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); 158 out->addCoverageFP(skstd::make_unique<ClipFP>(proxyProvider, fTest, fAtlas)); 159 return true; 160 } 161 bool quickContains(const SkRect&) const final { return false; } 162 bool isRRect(const SkRect& rtBounds, SkRRect* rr, GrAA*) const final { return false; } 163 void getConservativeBounds(int width, int height, SkIRect* rect, bool* iior) const final { 164 rect->set(0, 0, width, height); 165 if (iior) { 166 *iior = false; 167 } 168 } 169 170 LazyProxyTest* const fTest; 171 GrTextureProxy* fAtlas; 172 }; 173 174private: 175 skiatest::Reporter* fReporter; 176 bool fHasOpTexture; 177 bool fHasClipTexture; 178}; 179 180DEF_GPUTEST(LazyProxyTest, reporter, /* options */) { 181 GrMockOptions mockOptions; 182 mockOptions.fConfigOptions[kAlpha_half_GrPixelConfig].fRenderable[0] = true; 183 mockOptions.fConfigOptions[kAlpha_half_GrPixelConfig].fTexturable = true; 184 sk_sp<GrContext> ctx = GrContext::MakeMock(&mockOptions, GrContextOptions()); 185 GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider(); 186 for (bool nullTexture : {false, true}) { 187 LazyProxyTest test(reporter); 188 ctx->contextPriv().addOnFlushCallbackObject(&test); 189 sk_sp<GrRenderTargetContext> rtc = 190 ctx->makeDeferredRenderTargetContext(SkBackingFit::kExact, 100, 100, 191 kRGBA_8888_GrPixelConfig, nullptr); 192 REPORTER_ASSERT(reporter, rtc); 193 sk_sp<GrRenderTargetContext> mockAtlas = 194 ctx->makeDeferredRenderTargetContext(SkBackingFit::kExact, 10, 10, 195 kAlpha_half_GrPixelConfig, nullptr); 196 REPORTER_ASSERT(reporter, mockAtlas); 197 rtc->priv().testingOnly_addDrawOp(LazyProxyTest::Clip(&test, mockAtlas->asTextureProxy()), 198 skstd::make_unique<LazyProxyTest::Op>(proxyProvider, &test, nullTexture)); 199 ctx->contextPriv().testingOnly_flushAndRemoveOnFlushCallbackObject(&test); 200 } 201} 202 203static const int kSize = 16; 204 205DEF_GPUTEST(LazyProxyReleaseTest, reporter, /* options */) { 206 GrMockOptions mockOptions; 207 sk_sp<GrContext> ctx = GrContext::MakeMock(&mockOptions, GrContextOptions()); 208 auto proxyProvider = ctx->contextPriv().proxyProvider(); 209 210 GrSurfaceDesc desc; 211 desc.fWidth = kSize; 212 desc.fHeight = kSize; 213 desc.fConfig = kRGBA_8888_GrPixelConfig; 214 215 for (bool doInstantiate : {true, false}) { 216 int testCount = 0; 217 int* testCountPtr = &testCount; 218 sk_sp<GrTextureProxy> proxy = proxyProvider->createLazyProxy( 219 [testCountPtr](GrResourceProvider* resourceProvider, GrSurfaceOrigin* outOrigin) { 220 if (!resourceProvider) { 221 *testCountPtr = -1; 222 return sk_sp<GrTexture>(); 223 } 224 *testCountPtr = 1; 225 return sk_sp<GrTexture>(); 226 }, desc, GrMipMapped::kNo, SkBackingFit::kExact, SkBudgeted::kNo); 227 228 REPORTER_ASSERT(reporter, 0 == testCount); 229 230 if (doInstantiate) { 231 proxy->priv().doLazyInstantiation(ctx->contextPriv().resourceProvider()); 232 REPORTER_ASSERT(reporter, 1 == testCount); 233 proxy.reset(); 234 REPORTER_ASSERT(reporter, -1 == testCount); 235 } else { 236 proxy.reset(); 237 REPORTER_ASSERT(reporter, -1 == testCount); 238 } 239 } 240} 241 242class LazyFailedInstantiationTestOp : public GrDrawOp { 243public: 244 DEFINE_OP_CLASS_ID 245 246 LazyFailedInstantiationTestOp(GrProxyProvider* proxyProvider, int* testExecuteValue, 247 bool shouldFailInstantiation) 248 : INHERITED(ClassID()) 249 , fTestExecuteValue(testExecuteValue) { 250 GrSurfaceDesc desc; 251 desc.fWidth = kSize; 252 desc.fHeight = kSize; 253 desc.fConfig = kRGBA_8888_GrPixelConfig; 254 255 fLazyProxy = proxyProvider->createLazyProxy( 256 [testExecuteValue, shouldFailInstantiation, desc] ( 257 GrResourceProvider* rp, GrSurfaceOrigin* /*origin*/) { 258 if (!rp) { 259 return sk_sp<GrTexture>(); 260 } 261 if (shouldFailInstantiation) { 262 *testExecuteValue = 1; 263 return sk_sp<GrTexture>(); 264 } 265 return rp->createTexture(desc, SkBudgeted::kNo); 266 }, desc, GrMipMapped::kNo, SkBackingFit::kExact, SkBudgeted::kNo); 267 268 this->setBounds(SkRect::MakeIWH(kSize, kSize), 269 HasAABloat::kNo, IsZeroArea::kNo); 270 } 271 272 void visitProxies(const VisitProxyFunc& func) const override { 273 func(fLazyProxy.get()); 274 } 275 276private: 277 const char* name() const override { return "LazyFailedInstantiationTestOp"; } 278 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; } 279 RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*, 280 GrPixelConfigIsClamped) override { 281 return RequiresDstTexture::kNo; 282 } 283 bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; } 284 void onPrepare(GrOpFlushState*) override {} 285 void onExecute(GrOpFlushState* state) override { 286 *fTestExecuteValue = 2; 287 } 288 289 int* fTestExecuteValue; 290 sk_sp<GrSurfaceProxy> fLazyProxy; 291 292 typedef GrDrawOp INHERITED; 293}; 294 295// Test that when a lazy proxy fails to instantiate during flush that we drop the Op that it was 296// associated with. 297DEF_GPUTEST(LazyProxyFailedInstantiationTest, reporter, /* options */) { 298 GrMockOptions mockOptions; 299 sk_sp<GrContext> ctx = GrContext::MakeMock(&mockOptions, GrContextOptions()); 300 GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider(); 301 for (bool failInstantiation : {false, true}) { 302 sk_sp<GrRenderTargetContext> rtc = 303 ctx->makeDeferredRenderTargetContext(SkBackingFit::kExact, 100, 100, 304 kRGBA_8888_GrPixelConfig, nullptr); 305 REPORTER_ASSERT(reporter, rtc); 306 307 rtc->clear(nullptr, 0xbaaaaaad, GrRenderTargetContext::CanClearFullscreen::kYes); 308 309 int executeTestValue = 0; 310 rtc->priv().testingOnly_addDrawOp( 311 skstd::make_unique<LazyFailedInstantiationTestOp>(proxyProvider, &executeTestValue, 312 failInstantiation)); 313 ctx->flush(); 314 315 if (failInstantiation) { 316#ifdef SK_DISABLE_EXPLICIT_GPU_RESOURCE_ALLOCATION 317 // When we disable explicit gpu resource allocation we don't throw away ops that have 318 // uninstantiated proxies. 319 REPORTER_ASSERT(reporter, 2 == executeTestValue); 320#else 321 REPORTER_ASSERT(reporter, 1 == executeTestValue); 322#endif 323 } else { 324 REPORTER_ASSERT(reporter, 2 == executeTestValue); 325 } 326 } 327 328} 329 330#endif 331