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// This is a GPU-backend specific test. 9 10#include "Test.h" 11 12#if SK_SUPPORT_GPU 13 14#include "GrBackendSurface.h" 15#include "GrContextPriv.h" 16#include "GrResourceCache.h" 17#include "GrProxyProvider.h" 18#include "GrResourceProvider.h" 19#include "GrTest.h" 20#include "GrTexture.h" 21#include "GrTextureProxy.h" 22 23#include "SkGr.h" 24#include "SkImage.h" 25 26int GrProxyProvider::numUniqueKeyProxies_TestOnly() const { 27 return fUniquelyKeyedProxies.count(); 28} 29 30static GrSurfaceDesc make_desc(GrSurfaceFlags flags) { 31 GrSurfaceDesc desc; 32 desc.fFlags = flags; 33 desc.fOrigin = kBottomLeft_GrSurfaceOrigin; 34 desc.fWidth = 64; 35 desc.fHeight = 64; 36 desc.fConfig = kRGBA_8888_GrPixelConfig; 37 desc.fSampleCnt = 1; 38 39 return desc; 40} 41 42/////////////////////////////////////////////////////////////////////////////////////////////////// 43// Basic test 44 45static sk_sp<GrTextureProxy> deferred_tex(skiatest::Reporter* reporter, 46 GrProxyProvider* proxyProvider, SkBackingFit fit) { 47 const GrSurfaceDesc desc = make_desc(kNone_GrSurfaceFlags); 48 49 sk_sp<GrTextureProxy> proxy = proxyProvider->createProxy(desc, fit, SkBudgeted::kYes); 50 // Only budgeted & wrapped external proxies get to carry uniqueKeys 51 REPORTER_ASSERT(reporter, !proxy->getUniqueKey().isValid()); 52 return proxy; 53} 54 55static sk_sp<GrTextureProxy> deferred_texRT(skiatest::Reporter* reporter, 56 GrProxyProvider* proxyProvider, SkBackingFit fit) { 57 const GrSurfaceDesc desc = make_desc(kRenderTarget_GrSurfaceFlag); 58 59 sk_sp<GrTextureProxy> proxy = proxyProvider->createProxy(desc, fit, SkBudgeted::kYes); 60 // Only budgeted & wrapped external proxies get to carry uniqueKeys 61 REPORTER_ASSERT(reporter, !proxy->getUniqueKey().isValid()); 62 return proxy; 63} 64 65static sk_sp<GrTextureProxy> wrapped(skiatest::Reporter* reporter, 66 GrProxyProvider* proxyProvider, SkBackingFit fit) { 67 const GrSurfaceDesc desc = make_desc(kNone_GrSurfaceFlags); 68 69 sk_sp<GrTextureProxy> proxy = proxyProvider->createInstantiatedProxy(desc, fit, 70 SkBudgeted::kYes); 71 // Only budgeted & wrapped external proxies get to carry uniqueKeys 72 REPORTER_ASSERT(reporter, !proxy->getUniqueKey().isValid()); 73 return proxy; 74} 75 76static sk_sp<GrTextureProxy> wrapped_with_key(skiatest::Reporter* reporter, 77 GrProxyProvider* proxyProvider, SkBackingFit fit) { 78 static GrUniqueKey::Domain d = GrUniqueKey::GenerateDomain(); 79 static int kUniqueKeyData = 0; 80 81 GrUniqueKey key; 82 83 GrUniqueKey::Builder builder(&key, d, 1, nullptr); 84 builder[0] = kUniqueKeyData++; 85 builder.finish(); 86 87 const GrSurfaceDesc desc = make_desc(kNone_GrSurfaceFlags); 88 89 // Only budgeted & wrapped external proxies get to carry uniqueKeys 90 sk_sp<GrTextureProxy> proxy = proxyProvider->createInstantiatedProxy(desc, fit, 91 SkBudgeted::kYes, 0); 92 SkAssertResult(proxyProvider->assignUniqueKeyToProxy(key, proxy.get())); 93 REPORTER_ASSERT(reporter, proxy->getUniqueKey().isValid()); 94 return proxy; 95} 96 97static sk_sp<GrTextureProxy> create_wrapped_backend(GrContext* context, SkBackingFit fit, 98 sk_sp<GrTexture>* backingSurface) { 99 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); 100 GrResourceProvider* resourceProvider = context->contextPriv().resourceProvider(); 101 102 const GrSurfaceDesc desc = make_desc(kNone_GrSurfaceFlags); 103 104 *backingSurface = resourceProvider->createTexture(desc, SkBudgeted::kNo); 105 if (!(*backingSurface)) { 106 return nullptr; 107 } 108 109 GrBackendTexture backendTex = (*backingSurface)->getBackendTexture(); 110 111 return proxyProvider->createWrappedTextureProxy(backendTex, kBottomLeft_GrSurfaceOrigin); 112} 113 114 115// This tests the basic capabilities of the uniquely keyed texture proxies. Does assigning 116// and looking them up work, etc. 117static void basic_test(GrContext* context, 118 skiatest::Reporter* reporter, 119 sk_sp<GrTextureProxy> proxy, bool proxyIsCached) { 120 static int id = 1; 121 122 GrResourceProvider* resourceProvider = context->contextPriv().resourceProvider(); 123 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); 124 GrResourceCache* cache = context->contextPriv().getResourceCache(); 125 126 int startCacheCount = cache->getResourceCount(); 127 128 GrUniqueKey key; 129 if (proxy->getUniqueKey().isValid()) { 130 key = proxy->getUniqueKey(); 131 } else { 132 GrMakeKeyFromImageID(&key, id, SkIRect::MakeWH(64, 64)); 133 ++id; 134 135 // Assigning the uniqueKey adds the proxy to the hash but doesn't force instantiation 136 REPORTER_ASSERT(reporter, !proxyProvider->numUniqueKeyProxies_TestOnly()); 137 SkAssertResult(proxyProvider->assignUniqueKeyToProxy(key, proxy.get())); 138 } 139 140 REPORTER_ASSERT(reporter, 1 == proxyProvider->numUniqueKeyProxies_TestOnly()); 141 REPORTER_ASSERT(reporter, startCacheCount == cache->getResourceCount()); 142 143 // setUniqueKey had better stick 144 REPORTER_ASSERT(reporter, key == proxy->getUniqueKey()); 145 146 // We just added it, surely we can find it 147 REPORTER_ASSERT(reporter, proxyProvider->findOrCreateProxyByUniqueKey( 148 key, kBottomLeft_GrSurfaceOrigin)); 149 REPORTER_ASSERT(reporter, 1 == proxyProvider->numUniqueKeyProxies_TestOnly()); 150 151 // Once instantiated, the backing resource should have the same key 152 SkAssertResult(proxy->instantiate(resourceProvider)); 153 const GrUniqueKey& texKey = proxy->priv().peekSurface()->getUniqueKey(); 154 REPORTER_ASSERT(reporter, texKey.isValid()); 155 REPORTER_ASSERT(reporter, key == texKey); 156 if (proxyIsCached) { 157 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 158 } 159 160 // deleting the proxy should delete it from the hash but not the cache 161 proxy = nullptr; 162 REPORTER_ASSERT(reporter, 0 == proxyProvider->numUniqueKeyProxies_TestOnly()); 163 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 164 165 // If the proxy was cached refinding it should bring it back to life 166 proxy = proxyProvider->findOrCreateProxyByUniqueKey(key, kBottomLeft_GrSurfaceOrigin); 167 if (proxyIsCached) { 168 REPORTER_ASSERT(reporter, proxy); 169 REPORTER_ASSERT(reporter, 1 == proxyProvider->numUniqueKeyProxies_TestOnly()); 170 } else { 171 REPORTER_ASSERT(reporter, !proxy); 172 REPORTER_ASSERT(reporter, 0 == proxyProvider->numUniqueKeyProxies_TestOnly()); 173 } 174 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 175 176 // Mega-purging it should remove it from both the hash and the cache 177 proxy = nullptr; 178 cache->purgeAllUnlocked(); 179 if (proxyIsCached) { 180 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 181 } else { 182 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 183 } 184 185 // We can bring neither the texture nor proxy back from perma-death 186 proxy = proxyProvider->findOrCreateProxyByUniqueKey(key, kBottomLeft_GrSurfaceOrigin); 187 REPORTER_ASSERT(reporter, !proxy); 188 if (proxyIsCached) { 189 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 190 } else { 191 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 192 } 193} 194 195/////////////////////////////////////////////////////////////////////////////////////////////////// 196// Invalidation test 197 198// Test if invalidating unique ids operates as expected for texture proxies. 199static void invalidation_test(GrContext* context, skiatest::Reporter* reporter) { 200 201 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); 202 GrResourceCache* cache = context->contextPriv().getResourceCache(); 203 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 204 205 sk_sp<SkImage> rasterImg; 206 207 { 208 SkImageInfo ii = SkImageInfo::Make(64, 64, kRGBA_8888_SkColorType, kOpaque_SkAlphaType); 209 210 SkBitmap bm; 211 bm.allocPixels(ii); 212 213 rasterImg = SkImage::MakeFromBitmap(bm); 214 REPORTER_ASSERT(reporter, 0 == proxyProvider->numUniqueKeyProxies_TestOnly()); 215 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 216 } 217 218 sk_sp<SkImage> textureImg = rasterImg->makeTextureImage(context, nullptr); 219 REPORTER_ASSERT(reporter, 1 == proxyProvider->numUniqueKeyProxies_TestOnly()); 220 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 221 222 rasterImg = nullptr; // this invalidates the uniqueKey 223 224 // this forces the cache to respond to the inval msg 225 int maxNum; 226 size_t maxBytes; 227 context->getResourceCacheLimits(&maxNum, &maxBytes); 228 context->setResourceCacheLimits(maxNum-1, maxBytes); 229 230 REPORTER_ASSERT(reporter, 0 == proxyProvider->numUniqueKeyProxies_TestOnly()); 231 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 232 233 textureImg = nullptr; 234 context->purgeAllUnlockedResources(); 235 236 REPORTER_ASSERT(reporter, 0 == proxyProvider->numUniqueKeyProxies_TestOnly()); 237 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 238} 239 240#ifndef SK_DISABLE_DEFERRED_PROXIES 241// Test if invalidating unique ids prior to instantiating operates as expected 242static void invalidation_and_instantiation_test(GrContext* context, skiatest::Reporter* reporter) { 243 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); 244 GrResourceProvider* resourceProvider = context->contextPriv().resourceProvider(); 245 GrResourceCache* cache = context->contextPriv().getResourceCache(); 246 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 247 248 static GrUniqueKey::Domain d = GrUniqueKey::GenerateDomain(); 249 GrUniqueKey key; 250 GrUniqueKey::Builder builder(&key, d, 1, nullptr); 251 builder[0] = 0; 252 builder.finish(); 253 254 // Create proxy, assign unique key 255 sk_sp<GrTextureProxy> proxy = deferred_tex(reporter, proxyProvider, SkBackingFit::kExact); 256 SkAssertResult(proxyProvider->assignUniqueKeyToProxy(key, proxy.get())); 257 258 // Send an invalidation message, which will be sitting in the cache's inbox 259 SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(GrUniqueKeyInvalidatedMessage(key)); 260 261 REPORTER_ASSERT(reporter, 1 == proxyProvider->numUniqueKeyProxies_TestOnly()); 262 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 263 264 // Instantiate the proxy. This will trigger the message to be processed, so the resulting 265 // texture should *not* have the unique key on it! 266 SkAssertResult(proxy->instantiate(resourceProvider)); 267 268 REPORTER_ASSERT(reporter, !proxy->getUniqueKey().isValid()); 269 REPORTER_ASSERT(reporter, !proxy->priv().peekTexture()->getUniqueKey().isValid()); 270 REPORTER_ASSERT(reporter, 0 == proxyProvider->numUniqueKeyProxies_TestOnly()); 271 REPORTER_ASSERT(reporter, 1 == cache->getResourceCount()); 272 273 proxy = nullptr; 274 context->purgeAllUnlockedResources(); 275 276 REPORTER_ASSERT(reporter, 0 == proxyProvider->numUniqueKeyProxies_TestOnly()); 277 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 278} 279#endif 280 281DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TextureProxyTest, reporter, ctxInfo) { 282 GrContext* context = ctxInfo.grContext(); 283 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); 284 GrResourceCache* cache = context->contextPriv().getResourceCache(); 285 286 REPORTER_ASSERT(reporter, !proxyProvider->numUniqueKeyProxies_TestOnly()); 287 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 288 289 for (auto fit : { SkBackingFit::kExact, SkBackingFit::kApprox }) { 290 for (auto create : { deferred_tex, deferred_texRT, wrapped, wrapped_with_key }) { 291 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 292 basic_test(context, reporter, create(reporter, proxyProvider, fit), true); 293 } 294 295 REPORTER_ASSERT(reporter, 0 == cache->getResourceCount()); 296 sk_sp<GrTexture> backingTex; 297 sk_sp<GrTextureProxy> proxy = create_wrapped_backend(context, fit, &backingTex); 298 basic_test(context, reporter, std::move(proxy), false); 299 300 backingTex = nullptr; 301 cache->purgeAllUnlocked(); 302 } 303 304 invalidation_test(context, reporter); 305#ifndef SK_DISABLE_DEFERRED_PROXIES 306 invalidation_and_instantiation_test(context, reporter); 307#endif 308} 309 310#endif 311