GrProxyProvider.cpp revision a4ead65e2c80b6e649f31e28e8fa116aca83fad4
1/* 2 * Copyright 2018 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 "GrProxyProvider.h" 9 10#include "GrCaps.h" 11#include "GrRenderTarget.h" 12#include "GrResourceKey.h" 13#include "GrResourceProvider.h" 14#include "GrSurfaceProxy.h" 15#include "GrSurfaceProxyPriv.h" 16#include "GrTexture.h" 17#include "GrTextureProxyCacheAccess.h" 18#include "GrTextureRenderTargetProxy.h" 19#include "../private/GrSingleOwner.h" 20#include "SkBitmap.h" 21#include "SkGr.h" 22#include "SkImage.h" 23#include "SkImage_Base.h" 24#include "SkImageInfoPriv.h" 25#include "SkImagePriv.h" 26#include "SkMipMap.h" 27#include "SkTraceEvent.h" 28 29#define ASSERT_SINGLE_OWNER \ 30 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);) 31 32GrProxyProvider::GrProxyProvider(GrResourceProvider* resourceProvider, 33 GrResourceCache* resourceCache, 34 sk_sp<const GrCaps> caps, 35 GrSingleOwner* owner) 36 : fResourceProvider(resourceProvider) 37 , fResourceCache(resourceCache) 38 , fAbandoned(false) 39 , fCaps(caps) 40#ifdef SK_DEBUG 41 , fSingleOwner(owner) 42#endif 43{ 44 45} 46 47GrProxyProvider::~GrProxyProvider() { 48 SkASSERT(!fUniquelyKeyedProxies.count()); 49} 50 51bool GrProxyProvider::assignUniqueKeyToProxy(const GrUniqueKey& key, GrTextureProxy* proxy) { 52 ASSERT_SINGLE_OWNER 53 SkASSERT(key.isValid()); 54 if (this->isAbandoned() || !proxy) { 55 return false; 56 } 57 58 // If there is already a GrResource with this key then the caller has violated the normal 59 // usage pattern of uniquely keyed resources (e.g., they have created one w/o first seeing 60 // if it already existed in the cache). 61 SkASSERT(!fResourceCache || !fResourceCache->findAndRefUniqueResource(key)); 62 63 // Uncached resources can never have a unique key, unless they're wrapped resources. Wrapped 64 // resources are a special case: the unique keys give us a weak ref so that we can reuse the 65 // same resource (rather than re-wrapping). When a wrapped resource is no longer referenced, 66 // it will always be released - it is never converted to a scratch resource. 67 if (SkBudgeted::kNo == proxy->isBudgeted() && 68 (!proxy->priv().isInstantiated() || 69 !proxy->priv().peekSurface()->resourcePriv().refsWrappedObjects())) { 70 return false; 71 } 72 73 SkASSERT(!fUniquelyKeyedProxies.find(key)); // multiple proxies can't get the same key 74 75 proxy->cacheAccess().setUniqueKey(this, key); 76 SkASSERT(proxy->getUniqueKey() == key); 77 fUniquelyKeyedProxies.add(proxy); 78 return true; 79} 80 81void GrProxyProvider::adoptUniqueKeyFromSurface(GrTextureProxy* proxy, const GrSurface* surf) { 82 SkASSERT(surf->getUniqueKey().isValid()); 83 proxy->cacheAccess().setUniqueKey(this, surf->getUniqueKey()); 84 SkASSERT(proxy->getUniqueKey() == surf->getUniqueKey()); 85 // multiple proxies can't get the same key 86 SkASSERT(!fUniquelyKeyedProxies.find(surf->getUniqueKey())); 87 fUniquelyKeyedProxies.add(proxy); 88} 89 90void GrProxyProvider::removeUniqueKeyFromProxy(const GrUniqueKey& key, GrTextureProxy* proxy) { 91 ASSERT_SINGLE_OWNER 92 if (this->isAbandoned() || !proxy) { 93 return; 94 } 95 this->processInvalidProxyUniqueKey(key, proxy, true); 96} 97 98sk_sp<GrTextureProxy> GrProxyProvider::findProxyByUniqueKey(const GrUniqueKey& key, 99 GrSurfaceOrigin origin) { 100 ASSERT_SINGLE_OWNER 101 102 if (this->isAbandoned()) { 103 return nullptr; 104 } 105 106 sk_sp<GrTextureProxy> result = sk_ref_sp(fUniquelyKeyedProxies.find(key)); 107 if (result) { 108 SkASSERT(result->origin() == origin); 109 } 110 return result; 111} 112 113sk_sp<GrTextureProxy> GrProxyProvider::createWrapped(sk_sp<GrTexture> tex, GrSurfaceOrigin origin) { 114#ifdef SK_DEBUG 115 if (tex->getUniqueKey().isValid()) { 116 SkASSERT(!this->findProxyByUniqueKey(tex->getUniqueKey(), origin)); 117 } 118#endif 119 120 if (tex->asRenderTarget()) { 121 return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(std::move(tex), origin)); 122 } else { 123 return sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(tex), origin)); 124 } 125} 126 127sk_sp<GrTextureProxy> GrProxyProvider::findOrCreateProxyByUniqueKey(const GrUniqueKey& key, 128 GrSurfaceOrigin origin) { 129 ASSERT_SINGLE_OWNER 130 131 if (this->isAbandoned()) { 132 return nullptr; 133 } 134 135 sk_sp<GrTextureProxy> result = this->findProxyByUniqueKey(key, origin); 136 if (result) { 137 return result; 138 } 139 140 if (!fResourceCache) { 141 return nullptr; 142 } 143 144 GrGpuResource* resource = fResourceCache->findAndRefUniqueResource(key); 145 if (!resource) { 146 return nullptr; 147 } 148 149 sk_sp<GrTexture> texture(static_cast<GrSurface*>(resource)->asTexture()); 150 SkASSERT(texture); 151 152 result = this->createWrapped(std::move(texture), origin); 153 SkASSERT(result->getUniqueKey() == key); 154 // createWrapped should've added this for us 155 SkASSERT(fUniquelyKeyedProxies.find(key)); 156 return result; 157} 158 159sk_sp<GrTextureProxy> GrProxyProvider::createInstantiatedProxy(const GrSurfaceDesc& desc, 160 SkBackingFit fit, 161 SkBudgeted budgeted, 162 uint32_t flags) { 163 sk_sp<GrTexture> tex; 164 165 if (SkBackingFit::kApprox == fit) { 166 tex = fResourceProvider->createApproxTexture(desc, flags); 167 } else { 168 tex = fResourceProvider->createTexture(desc, budgeted, flags); 169 } 170 if (!tex) { 171 return nullptr; 172 } 173 174 return this->createWrapped(std::move(tex), desc.fOrigin); 175} 176 177sk_sp<GrTextureProxy> GrProxyProvider::createTextureProxy(const GrSurfaceDesc& desc, 178 SkBudgeted budgeted, 179 const void* srcData, size_t rowBytes) { 180 ASSERT_SINGLE_OWNER 181 182 if (this->isAbandoned()) { 183 return nullptr; 184 } 185 186 if (srcData) { 187 GrMipLevel mipLevel = { srcData, rowBytes }; 188 189 sk_sp<GrTexture> tex = fResourceProvider->createTexture(desc, budgeted, 190 SkBackingFit::kExact, mipLevel); 191 if (!tex) { 192 return nullptr; 193 } 194 195 return this->createWrapped(std::move(tex), desc.fOrigin); 196 } 197 198 return this->createProxy(desc, SkBackingFit::kExact, budgeted); 199} 200 201sk_sp<GrTextureProxy> GrProxyProvider::createTextureProxy(sk_sp<SkImage> srcImage, 202 GrSurfaceFlags flags, 203 GrSurfaceOrigin origin, 204 int sampleCnt, 205 SkBudgeted budgeted, 206 SkBackingFit fit) { 207 ASSERT_SINGLE_OWNER 208 SkASSERT(srcImage); 209 210 if (this->isAbandoned()) { 211 return nullptr; 212 } 213 214 GrSurfaceDesc desc; 215 desc.fWidth = srcImage->width(); 216 desc.fHeight = srcImage->height(); 217 desc.fFlags = flags; 218 desc.fOrigin = origin; 219 desc.fSampleCnt = sampleCnt; 220 desc.fConfig = SkImageInfo2GrPixelConfig(as_IB(srcImage)->onImageInfo(), *this->caps()); 221 222 sk_sp<GrTextureProxy> proxy = this->createLazyProxy( 223 [desc, budgeted, srcImage, fit] 224 (GrResourceProvider* resourceProvider, GrSurfaceOrigin* /*outOrigin*/) { 225 if (!resourceProvider) { 226 // Nothing to clean up here. Once the proxy (and thus lambda) is deleted the ref 227 // on srcImage will be released. 228 return sk_sp<GrTexture>(); 229 } 230 SkPixmap pixMap; 231 SkAssertResult(srcImage->peekPixels(&pixMap)); 232 GrMipLevel mipLevel = { pixMap.addr(), pixMap.rowBytes() }; 233 234 return resourceProvider->createTexture(desc, budgeted, fit, mipLevel); 235 }, desc, GrMipMapped::kNo, fit, budgeted); 236 237 if (fResourceProvider) { 238 // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however 239 // we're better off instantiating the proxy immediately here. 240 if (!proxy->priv().doLazyInstantiation(fResourceProvider)) { 241 return nullptr; 242 } 243 } 244 return proxy; 245} 246 247sk_sp<GrTextureProxy> GrProxyProvider::createMipMapProxy( 248 const GrSurfaceDesc& desc, SkBudgeted budgeted, 249 const GrMipLevel texels[], int mipLevelCount, 250 SkDestinationSurfaceColorMode mipColorMode) { 251 ASSERT_SINGLE_OWNER 252 253 if (this->isAbandoned()) { 254 return nullptr; 255 } 256 257 if (!mipLevelCount) { 258 if (texels) { 259 return nullptr; 260 } 261 return this->createProxy(desc, SkBackingFit::kExact, budgeted); 262 } 263 if (!texels) { 264 return nullptr; 265 } 266 267 if (1 == mipLevelCount) { 268 return this->createTextureProxy(desc, budgeted, texels[0].fPixels, texels[0].fRowBytes); 269 } 270 271#ifdef SK_DEBUG 272 // There are only three states we want to be in when uploading data to a mipped surface. 273 // 1) We have data to upload to all layers 274 // 2) We are not uploading data to any layers 275 // 3) We are only uploading data to the base layer 276 // We check here to make sure we do not have any other state. 277 bool firstLevelHasData = SkToBool(texels[0].fPixels); 278 bool allOtherLevelsHaveData = true, allOtherLevelsLackData = true; 279 for (int i = 1; i < mipLevelCount; ++i) { 280 if (texels[i].fPixels) { 281 allOtherLevelsLackData = false; 282 } else { 283 allOtherLevelsHaveData = false; 284 } 285 } 286 SkASSERT((firstLevelHasData && allOtherLevelsHaveData) || allOtherLevelsLackData); 287#endif 288 289 sk_sp<GrTexture> tex(fResourceProvider->createTexture(desc, budgeted, 290 texels, mipLevelCount, 291 mipColorMode)); 292 if (!tex) { 293 return nullptr; 294 } 295 296 return this->createWrapped(std::move(tex), desc.fOrigin); 297} 298 299sk_sp<GrTextureProxy> GrProxyProvider::createMipMapProxy(const GrSurfaceDesc& desc, 300 SkBudgeted budgeted) { 301 // SkMipMap doesn't include the base level in the level count so we have to add 1 302 int mipCount = SkMipMap::ComputeLevelCount(desc.fWidth, desc.fHeight) + 1; 303 304 std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipCount]); 305 306 // We don't want to upload any texel data 307 for (int i = 0; i < mipCount; i++) { 308 texels[i].fPixels = nullptr; 309 texels[i].fRowBytes = 0; 310 } 311 312 return this->createMipMapProxy(desc, budgeted, texels.get(), mipCount, 313 SkDestinationSurfaceColorMode::kLegacy); 314} 315 316sk_sp<GrTextureProxy> GrProxyProvider::createMipMapProxyFromBitmap(const SkBitmap& bitmap, 317 SkColorSpace* dstColorSpace) { 318 SkDestinationSurfaceColorMode mipColorMode = dstColorSpace 319 ? SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware 320 : SkDestinationSurfaceColorMode::kLegacy; 321 322 if (!SkImageInfoIsValid(bitmap.info(), mipColorMode)) { 323 return nullptr; 324 } 325 326 SkPixmap pixmap; 327 if (!bitmap.peekPixels(&pixmap)) { 328 return nullptr; 329 } 330 331 ATRACE_ANDROID_FRAMEWORK("Upload MipMap Texture [%ux%u]", pixmap.width(), pixmap.height()); 332 sk_sp<SkMipMap> mipmaps(SkMipMap::Build(pixmap, mipColorMode, nullptr)); 333 if (!mipmaps) { 334 return nullptr; 335 } 336 337 if (mipmaps->countLevels() < 0) { 338 return nullptr; 339 } 340 341 // In non-ddl we will always instantiate right away. Thus we never want to copy the SkBitmap 342 // even if its mutable. In ddl, if the bitmap is mutable then we must make a copy since the 343 // upload of the data to the gpu can happen at anytime and the bitmap may change by then. 344 SkCopyPixelsMode copyMode = fResourceProvider ? kNever_SkCopyPixelsMode 345 : kIfMutable_SkCopyPixelsMode; 346 sk_sp<SkImage> baseLevel = SkMakeImageFromRasterBitmap(bitmap, copyMode); 347 348 if (!baseLevel) { 349 return nullptr; 350 } 351 352 GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(pixmap.info(), *this->caps()); 353 354 if (0 == mipmaps->countLevels()) { 355 return this->createTextureProxy(baseLevel, kNone_GrSurfaceFlags, kTopLeft_GrSurfaceOrigin, 356 1, SkBudgeted::kYes, SkBackingFit::kExact); 357 358 } 359 360 sk_sp<GrTextureProxy> proxy = this->createLazyProxy( 361 [desc, baseLevel, mipmaps, mipColorMode] 362 (GrResourceProvider* resourceProvider, GrSurfaceOrigin* /*outOrigin*/) { 363 if (!resourceProvider) { 364 return sk_sp<GrTexture>(); 365 } 366 367 const int mipLevelCount = mipmaps->countLevels() + 1; 368 std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]); 369 370 SkPixmap pixmap; 371 SkAssertResult(baseLevel->peekPixels(&pixmap)); 372 373 // DDL TODO: Instead of copying all this info into GrMipLevels we should just plumb 374 // the use of SkMipMap down through Ganesh. 375 texels[0].fPixels = pixmap.addr(); 376 texels[0].fRowBytes = pixmap.rowBytes(); 377 378 for (int i = 1; i < mipLevelCount; ++i) { 379 SkMipMap::Level generatedMipLevel; 380 mipmaps->getLevel(i - 1, &generatedMipLevel); 381 texels[i].fPixels = generatedMipLevel.fPixmap.addr(); 382 texels[i].fRowBytes = generatedMipLevel.fPixmap.rowBytes(); 383 SkASSERT(texels[i].fPixels); 384 } 385 386 return resourceProvider->createTexture(desc, SkBudgeted::kYes, texels.get(), 387 mipLevelCount, mipColorMode); 388 }, desc, GrMipMapped::kYes, SkBackingFit::kExact, SkBudgeted::kYes); 389 390 if (fResourceProvider) { 391 // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however 392 // we're better off instantiating the proxy immediately here. 393 if (!proxy->priv().doLazyInstantiation(fResourceProvider)) { 394 return nullptr; 395 } 396 } 397 return proxy; 398} 399 400sk_sp<GrTextureProxy> GrProxyProvider::createProxy(const GrSurfaceDesc& desc, 401 SkBackingFit fit, 402 SkBudgeted budgeted, 403 uint32_t flags) { 404 SkASSERT(0 == flags || GrResourceProvider::kNoPendingIO_Flag == flags); 405 406 if (!this->caps()->validateSurfaceDesc(desc, GrMipMapped::kNo)) { 407 return nullptr; 408 } 409 GrSurfaceDesc copyDesc = desc; 410 if (desc.fFlags & kRenderTarget_GrSurfaceFlag) { 411 copyDesc.fSampleCnt = 412 this->caps()->getRenderTargetSampleCount(desc.fSampleCnt, desc.fConfig); 413 } 414 415 if (copyDesc.fFlags & kRenderTarget_GrSurfaceFlag) { 416 // We know anything we instantiate later from this deferred path will be 417 // both texturable and renderable 418 return sk_sp<GrTextureProxy>( 419 new GrTextureRenderTargetProxy(*this->caps(), copyDesc, fit, budgeted, flags)); 420 } 421 422 return sk_sp<GrTextureProxy>(new GrTextureProxy(copyDesc, fit, budgeted, nullptr, 0, flags)); 423} 424 425sk_sp<GrTextureProxy> GrProxyProvider::createWrappedTextureProxy( 426 const GrBackendTexture& backendTex, 427 GrSurfaceOrigin origin, 428 GrWrapOwnership ownership, 429 ReleaseProc releaseProc, 430 ReleaseContext releaseCtx) { 431 if (this->isAbandoned()) { 432 return nullptr; 433 } 434 435 GrSurfaceDesc desc; 436 desc.fOrigin = origin; 437 desc.fWidth = backendTex.width(); 438 desc.fHeight = backendTex.height(); 439 desc.fConfig = backendTex.config(); 440 GrMipMapped mipMapped = backendTex.hasMipMaps() ? GrMipMapped::kYes : GrMipMapped::kNo; 441 442 sk_sp<GrReleaseProcHelper> releaseHelper; 443 if (releaseProc) { 444 releaseHelper.reset(new GrReleaseProcHelper(releaseProc, releaseCtx)); 445 } 446 447 sk_sp<GrTextureProxy> proxy = this->createLazyProxy( 448 [backendTex, ownership, releaseHelper] 449 (GrResourceProvider* resourceProvider, GrSurfaceOrigin* /*outOrigin*/) { 450 if (!resourceProvider) { 451 // If this had a releaseHelper it will get unrefed when we delete this lambda 452 // and will call the release proc so that the client knows they can free the 453 // underlying backend object. 454 return sk_sp<GrTexture>(); 455 } 456 457 sk_sp<GrTexture> tex = resourceProvider->wrapBackendTexture(backendTex, 458 ownership); 459 if (!tex) { 460 return sk_sp<GrTexture>(); 461 } 462 if (releaseHelper) { 463 // This gives the texture a ref on the releaseHelper 464 tex->setRelease(releaseHelper); 465 } 466 SkASSERT(!tex->asRenderTarget()); // Strictly a GrTexture 467 // Make sure we match how we created the proxy with SkBudgeted::kNo 468 SkASSERT(SkBudgeted::kNo == tex->resourcePriv().isBudgeted()); 469 470 return tex; 471 }, desc, mipMapped, SkBackingFit::kExact, SkBudgeted::kNo); 472 473 if (fResourceProvider) { 474 // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however, 475 // we're better off instantiating the proxy immediately here. 476 if (!proxy->priv().doLazyInstantiation(fResourceProvider)) { 477 return nullptr; 478 } 479 } 480 return proxy; 481} 482 483sk_sp<GrTextureProxy> GrProxyProvider::createWrappedTextureProxy(const GrBackendTexture& tex, 484 GrSurfaceOrigin origin, 485 int sampleCnt) { 486 if (this->isAbandoned()) { 487 return nullptr; 488 } 489 490 sk_sp<GrTexture> texture(fResourceProvider->wrapRenderableBackendTexture(tex, sampleCnt)); 491 if (!texture) { 492 return nullptr; 493 } 494 SkASSERT(texture->asRenderTarget()); // A GrTextureRenderTarget 495 496 return this->createWrapped(std::move(texture), origin); 497} 498 499sk_sp<GrSurfaceProxy> GrProxyProvider::createWrappedRenderTargetProxy( 500 const GrBackendRenderTarget& backendRT, 501 GrSurfaceOrigin origin) { 502 if (this->isAbandoned()) { 503 return nullptr; 504 } 505 506 sk_sp<GrRenderTarget> rt(fResourceProvider->wrapBackendRenderTarget(backendRT)); 507 if (!rt) { 508 return nullptr; 509 } 510 SkASSERT(!rt->asTexture()); // Strictly a GrRenderTarget 511 SkASSERT(!rt->getUniqueKey().isValid()); 512 513 return sk_sp<GrSurfaceProxy>(new GrRenderTargetProxy(std::move(rt), origin)); 514} 515 516sk_sp<GrSurfaceProxy> GrProxyProvider::createWrappedRenderTargetProxy(const GrBackendTexture& tex, 517 GrSurfaceOrigin origin, 518 int sampleCnt) { 519 if (this->isAbandoned()) { 520 return nullptr; 521 } 522 523 sk_sp<GrRenderTarget> rt(fResourceProvider->wrapBackendTextureAsRenderTarget(tex, sampleCnt)); 524 if (!rt) { 525 return nullptr; 526 } 527 SkASSERT(!rt->asTexture()); // Strictly a GrRenderTarget 528 SkASSERT(!rt->getUniqueKey().isValid()); 529 530 return sk_sp<GrSurfaceProxy>(new GrRenderTargetProxy(std::move(rt), origin)); 531} 532 533sk_sp<GrTextureProxy> GrProxyProvider::createLazyProxy(LazyInstantiateCallback&& callback, 534 const GrSurfaceDesc& desc, 535 GrMipMapped mipMapped, 536 SkBackingFit fit, SkBudgeted budgeted) { 537 SkASSERT((desc.fWidth <= 0 && desc.fHeight <= 0) || 538 (desc.fWidth > 0 && desc.fHeight > 0)); 539 uint32_t flags = GrResourceProvider::kNoPendingIO_Flag; 540 return sk_sp<GrTextureProxy>(SkToBool(kRenderTarget_GrSurfaceFlag & desc.fFlags) ? 541 new GrTextureRenderTargetProxy(std::move(callback), desc, 542 mipMapped, fit, budgeted, flags) : 543 new GrTextureProxy(std::move(callback), desc, mipMapped, fit, 544 budgeted, flags)); 545} 546 547sk_sp<GrRenderTargetProxy> GrProxyProvider::createLazyRenderTargetProxy( 548 LazyInstantiateCallback&& callback, 549 const GrSurfaceDesc& desc, 550 Textureable textureable, 551 GrMipMapped mipMapped, 552 SkBackingFit fit, SkBudgeted budgeted) { 553 SkASSERT((desc.fWidth <= 0 && desc.fHeight <= 0) || 554 (desc.fWidth > 0 && desc.fHeight > 0)); 555 uint32_t flags = GrResourceProvider::kNoPendingIO_Flag; 556 if (Textureable::kYes == textureable) { 557 return sk_sp<GrRenderTargetProxy>(new GrTextureRenderTargetProxy(std::move(callback), desc, 558 mipMapped, fit, budgeted, 559 flags)); 560 } 561 562 return sk_sp<GrRenderTargetProxy>(new GrRenderTargetProxy(std::move(callback), desc, 563 fit, budgeted, flags)); 564} 565 566sk_sp<GrTextureProxy> GrProxyProvider::createFullyLazyProxy(LazyInstantiateCallback&& callback, 567 Renderable renderable, 568 GrPixelConfig config) { 569 GrSurfaceDesc desc; 570 if (Renderable::kYes == renderable) { 571 desc.fFlags = kRenderTarget_GrSurfaceFlag; 572 } 573 desc.fOrigin = kTopLeft_GrSurfaceOrigin; 574 desc.fWidth = -1; 575 desc.fHeight = -1; 576 desc.fConfig = config; 577 desc.fSampleCnt = 1; 578 579 return this->createLazyProxy(std::move(callback), desc, GrMipMapped::kNo, 580 SkBackingFit::kApprox, SkBudgeted::kYes); 581 582} 583 584bool GrProxyProvider::IsFunctionallyExact(GrSurfaceProxy* proxy) { 585 return proxy->priv().isExact() || (SkIsPow2(proxy->width()) && SkIsPow2(proxy->height())); 586} 587 588void GrProxyProvider::processInvalidProxyUniqueKey(const GrUniqueKey& key) { 589 // Note: this method is called for the whole variety of GrGpuResources so often 'key' 590 // will not be in 'fUniquelyKeyedProxies'. 591 GrTextureProxy* proxy = fUniquelyKeyedProxies.find(key); 592 if (proxy) { 593 this->processInvalidProxyUniqueKey(key, proxy, false); 594 } 595} 596 597void GrProxyProvider::processInvalidProxyUniqueKey(const GrUniqueKey& key, GrTextureProxy* proxy, 598 bool invalidateSurface) { 599 SkASSERT(proxy); 600 SkASSERT(proxy->getUniqueKey().isValid()); 601 SkASSERT(proxy->getUniqueKey() == key); 602 603 fUniquelyKeyedProxies.remove(key); 604 proxy->cacheAccess().clearUniqueKey(); 605 606 if (invalidateSurface && proxy->priv().isInstantiated()) { 607 GrSurface* surface = proxy->priv().peekSurface(); 608 if (surface) { 609 surface->resourcePriv().removeUniqueKey(); 610 } 611 } 612} 613 614void GrProxyProvider::removeAllUniqueKeys() { 615 UniquelyKeyedProxyHash::Iter iter(&fUniquelyKeyedProxies); 616 for (UniquelyKeyedProxyHash::Iter iter(&fUniquelyKeyedProxies); !iter.done(); ++iter) { 617 GrTextureProxy& tmp = *iter; 618 619 this->processInvalidProxyUniqueKey(tmp.getUniqueKey(), &tmp, false); 620 } 621 SkASSERT(!fUniquelyKeyedProxies.count()); 622} 623