/* * Copyright 2017 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ // This is a GPU-backend specific test. #include "Test.h" #if SK_SUPPORT_GPU #include "GrBackendSurface.h" #include "GrContextPriv.h" #include "GrResourceCache.h" #include "GrProxyProvider.h" #include "GrResourceProvider.h" #include "GrTest.h" #include "GrTexture.h" #include "GrTextureProxy.h" #include "SkGr.h" #include "SkImage.h" int GrProxyProvider::numUniqueKeyProxies_TestOnly() const { return fUniquelyKeyedProxies.count(); } static GrSurfaceDesc make_desc(GrSurfaceFlags flags) { GrSurfaceDesc desc; desc.fFlags = flags; desc.fOrigin = kBottomLeft_GrSurfaceOrigin; desc.fWidth = 64; desc.fHeight = 64; desc.fConfig = kRGBA_8888_GrPixelConfig; desc.fSampleCnt = 1; return desc; } /////////////////////////////////////////////////////////////////////////////////////////////////// // Basic test static sk_sp<GrTextureProxy> deferred_tex(skiatest::Reporter* reporter, GrProxyProvider* proxyProvider, SkBackingFit fit) { const GrSurfaceDesc desc = make_desc(kNone_GrSurfaceFlags); sk_sp<GrTextureProxy> proxy = proxyProvider->createProxy(desc, fit, SkBudgeted::kYes); // Only budgeted & wrapped external proxies get to carry uniqueKeys REPORTER_ASSERT(reporter, !proxy->getUniqueKey().isValid()); return proxy; } static sk_sp<GrTextureProxy> deferred_texRT(skiatest::Reporter* reporter, GrProxyProvider* proxyProvider, SkBackingFit fit) { const GrSurfaceDesc desc = make_desc(kRenderTarget_GrSurfaceFlag); sk_sp<GrTextureProxy> proxy = proxyProvider->createProxy(desc, fit, SkBudgeted::kYes); // Only budgeted & wrapped external proxies get to carry uniqueKeys REPORTER_ASSERT(reporter, !proxy->getUniqueKey().isValid()); return proxy; } static sk_sp<GrTextureProxy> wrapped(skiatest::Reporter* reporter, GrProxyProvider* proxyProvider, SkBackingFit fit) { const GrSurfaceDesc desc = make_desc(kNone_GrSurfaceFlags); sk_sp<GrTextureProxy> proxy = proxyProvider->createInstantiatedProxy(desc, fit, SkBudgeted::kYes); // Only budgeted & wrapped external proxies get to carry uniqueKeys REPORTER_ASSERT(reporter, !proxy->getUniqueKey().isValid()); return proxy; } static sk_sp<GrTextureProxy> wrapped_with_key(skiatest::Reporter* reporter, GrProxyProvider* proxyProvider, SkBackingFit fit) { static GrUniqueKey::Domain d = GrUniqueKey::GenerateDomain(); static int kUniqueKeyData = 0; GrUniqueKey key; GrUniqueKey::Builder builder(&key, d, 1, nullptr); builder[0] = kUniqueKeyData++; builder.finish(); const GrSurfaceDesc desc = make_desc(kNone_GrSurfaceFlags); // Only budgeted & wrapped external proxies get to carry uniqueKeys sk_sp<GrTextureProxy> proxy = proxyProvider->createInstantiatedProxy(desc, fit, SkBudgeted::kYes, 0); SkAssertResult(proxyProvider->assignUniqueKeyToProxy(key, proxy.get())); REPORTER_ASSERT(reporter, proxy->getUniqueKey().isValid()); return proxy; } static sk_sp<GrTextureProxy> create_wrapped_backend(GrContext* context, SkBackingFit fit, sk_sp<GrTexture>* backingSurface) { GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); GrResourceProvider* resourceProvider = context->contextPriv().resourceProvider(); const GrSurfaceDesc desc = make_desc(kNone_GrSurfaceFlags); *backingSurface = resourceProvider->createTexture(desc, SkBudgeted::kNo); if (!(*backingSurface)) { return nullptr; } GrBackendTexture backendTex = (*backingSurface)->getBackendTexture(); return proxyProvider->createWrappedTextureProxy(backendTex, kBottomLeft_GrSurfaceOrigin); } // This tests the basic capabilities of the uniquely keyed texture proxies. Does assigning // and looking them up work, etc. static void basic_test(GrContext* context, skiatest::Reporter* reporter, sk_sp<GrTextureProxy> proxy, bool proxyIsCached) { static int id = 1; GrResourceProvider* resourceProvider = context->contextPriv().resourceProvider(); GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); GrResourceCache* cache = context->contextPriv().getResourceCache(); int startCacheCount = cache->getResourceCount(); GrUniqueKey key; if (proxy->getUniqueKey().isValid()) { key = proxy->getUniqueKey(); } else { GrMakeKeyFromImageID(&key, id, SkIRect::MakeWH(64, 64)); ++id; // Assigning the uniqueKey adds the proxy to the hash but doesn't force instantiation REPORTER_ASSERT(reporter, !proxyProvider->numUniqueKeyProxies_TestOnly()); SkAssertResult(proxyProvider->assignUniqueKeyToProxy(key, proxy.get())); } REPORTER_ASSERT(reporter, 1 == proxyProvider->numUniqueKeyProxies_TestOnly()); REPORTER_ASSERT(reporter, startCacheCount == cache->getResourceCount()); // setUniqueKey had better stick REPORTER_ASSERT(reporter, key == proxy->getUniqueKey()); // We just added it, surely we can find it REPORTER_ASSERT(reporter, proxyProvider->findOrCreateProxyByUniqueKey( key, kBottomLeft_GrSurfaceOrigin)); REPORTER_ASSERT(reporter, 1 == proxyProvider->numUniqueKeyProxies_TestOnly()); // Once instantiated, the backing resource should have the same key SkAssertResult(proxy->instantiate(resourceProvider)); const GrUniqueKey& texKey = proxy->priv().peekSurface()->getUniqueKey(); REPORTER_ASSERT(reporter, texKey.isValid()); REPORTER_ASSERT(reporter, key == texKey); if (proxyIsCached) { REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); } // deleting the proxy should delete it from the hash but not the cache proxy = nullptr; REPORTER_ASSERT(reporter, 0 == proxyProvider->numUniqueKeyProxies_TestOnly()); REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); // If the proxy was cached refinding it should bring it back to life proxy = proxyProvider->findOrCreateProxyByUniqueKey(key, kBottomLeft_GrSurfaceOrigin); if (proxyIsCached) { REPORTER_ASSERT(reporter, proxy); REPORTER_ASSERT(reporter, 1 == proxyProvider->numUniqueKeyProxies_TestOnly()); } else { REPORTER_ASSERT(reporter, !proxy); REPORTER_ASSERT(reporter, 0 == proxyProvider->numUniqueKeyProxies_TestOnly()); } REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); // Mega-purging it should remove it from both the hash and the cache proxy = nullptr; cache->purgeAllUnlocked(); if (proxyIsCached) { REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); } else { REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); } // We can bring neither the texture nor proxy back from perma-death proxy = proxyProvider->findOrCreateProxyByUniqueKey(key, kBottomLeft_GrSurfaceOrigin); REPORTER_ASSERT(reporter, !proxy); if (proxyIsCached) { REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); } else { REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); } } /////////////////////////////////////////////////////////////////////////////////////////////////// // Invalidation test // Test if invalidating unique ids operates as expected for texture proxies. static void invalidation_test(GrContext* context, skiatest::Reporter* reporter) { GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); GrResourceCache* cache = context->contextPriv().getResourceCache(); REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); sk_sp<SkImage> rasterImg; { SkImageInfo ii = SkImageInfo::Make(64, 64, kRGBA_8888_SkColorType, kOpaque_SkAlphaType); SkBitmap bm; bm.allocPixels(ii); rasterImg = SkImage::MakeFromBitmap(bm); REPORTER_ASSERT(reporter, 0 == proxyProvider->numUniqueKeyProxies_TestOnly()); REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); } sk_sp<SkImage> textureImg = rasterImg->makeTextureImage(context, nullptr); REPORTER_ASSERT(reporter, 1 == proxyProvider->numUniqueKeyProxies_TestOnly()); REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); rasterImg = nullptr; // this invalidates the uniqueKey // this forces the cache to respond to the inval msg int maxNum; size_t maxBytes; context->getResourceCacheLimits(&maxNum, &maxBytes); context->setResourceCacheLimits(maxNum-1, maxBytes); REPORTER_ASSERT(reporter, 0 == proxyProvider->numUniqueKeyProxies_TestOnly()); REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); textureImg = nullptr; context->purgeAllUnlockedResources(); REPORTER_ASSERT(reporter, 0 == proxyProvider->numUniqueKeyProxies_TestOnly()); REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); } #ifndef SK_DISABLE_DEFERRED_PROXIES // Test if invalidating unique ids prior to instantiating operates as expected static void invalidation_and_instantiation_test(GrContext* context, skiatest::Reporter* reporter) { GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); GrResourceProvider* resourceProvider = context->contextPriv().resourceProvider(); GrResourceCache* cache = context->contextPriv().getResourceCache(); REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); static GrUniqueKey::Domain d = GrUniqueKey::GenerateDomain(); GrUniqueKey key; GrUniqueKey::Builder builder(&key, d, 1, nullptr); builder[0] = 0; builder.finish(); // Create proxy, assign unique key sk_sp<GrTextureProxy> proxy = deferred_tex(reporter, proxyProvider, SkBackingFit::kExact); SkAssertResult(proxyProvider->assignUniqueKeyToProxy(key, proxy.get())); // Send an invalidation message, which will be sitting in the cache's inbox SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(GrUniqueKeyInvalidatedMessage(key)); REPORTER_ASSERT(reporter, 1 == proxyProvider->numUniqueKeyProxies_TestOnly()); REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); // Instantiate the proxy. This will trigger the message to be processed, so the resulting // texture should *not* have the unique key on it! SkAssertResult(proxy->instantiate(resourceProvider)); REPORTER_ASSERT(reporter, !proxy->getUniqueKey().isValid()); REPORTER_ASSERT(reporter, !proxy->priv().peekTexture()->getUniqueKey().isValid()); REPORTER_ASSERT(reporter, 0 == proxyProvider->numUniqueKeyProxies_TestOnly()); REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); proxy = nullptr; context->purgeAllUnlockedResources(); REPORTER_ASSERT(reporter, 0 == proxyProvider->numUniqueKeyProxies_TestOnly()); REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); } #endif DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TextureProxyTest, reporter, ctxInfo) { GrContext* context = ctxInfo.grContext(); GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); GrResourceCache* cache = context->contextPriv().getResourceCache(); REPORTER_ASSERT(reporter, !proxyProvider->numUniqueKeyProxies_TestOnly()); REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); for (auto fit : { SkBackingFit::kExact, SkBackingFit::kApprox }) { for (auto create : { deferred_tex, deferred_texRT, wrapped, wrapped_with_key }) { REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); basic_test(context, reporter, create(reporter, proxyProvider, fit), true); } REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); sk_sp<GrTexture> backingTex; sk_sp<GrTextureProxy> proxy = create_wrapped_backend(context, fit, &backingTex); basic_test(context, reporter, std::move(proxy), false); backingTex = nullptr; cache->purgeAllUnlocked(); } invalidation_test(context, reporter); #ifndef SK_DISABLE_DEFERRED_PROXIES invalidation_and_instantiation_test(context, reporter); #endif } #endif