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 32 GrProxyProvider::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 47 GrProxyProvider::~GrProxyProvider() { 48 SkASSERT(!fUniquelyKeyedProxies.count()); 49 } 50 51 bool 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 81 void 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 90 void 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 98 sk_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 113 sk_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 127 sk_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 159 sk_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 177 sk_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 201 sk_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 GrPixelConfig config = SkImageInfo2GrPixelConfig(as_IB(srcImage)->onImageInfo(), 215 *this->caps()); 216 217 if (kUnknown_GrPixelConfig == config) { 218 return nullptr; 219 } 220 221 if (SkToBool(flags & kRenderTarget_GrSurfaceFlag)) { 222 sampleCnt = this->caps()->getRenderTargetSampleCount(sampleCnt, config); 223 if (!sampleCnt) { 224 return nullptr; 225 } 226 } 227 228 GrRenderTargetFlags renderTargetFlags = GrRenderTargetFlags::kNone; 229 if (SkToBool(flags & kRenderTarget_GrSurfaceFlag)) { 230 if (fCaps->usesMixedSamples() && sampleCnt > 1) { 231 renderTargetFlags |= GrRenderTargetFlags::kMixedSampled; 232 } 233 if (fCaps->maxWindowRectangles() > 0) { 234 renderTargetFlags |= GrRenderTargetFlags::kWindowRectsSupport; 235 } 236 } 237 238 GrSurfaceDesc desc; 239 desc.fWidth = srcImage->width(); 240 desc.fHeight = srcImage->height(); 241 desc.fFlags = flags; 242 desc.fOrigin = origin; 243 desc.fSampleCnt = sampleCnt; 244 desc.fConfig = config; 245 246 sk_sp<GrTextureProxy> proxy = this->createLazyProxy( 247 [desc, budgeted, srcImage, fit] 248 (GrResourceProvider* resourceProvider) { 249 if (!resourceProvider) { 250 // Nothing to clean up here. Once the proxy (and thus lambda) is deleted the ref 251 // on srcImage will be released. 252 return sk_sp<GrTexture>(); 253 } 254 SkPixmap pixMap; 255 SkAssertResult(srcImage->peekPixels(&pixMap)); 256 GrMipLevel mipLevel = { pixMap.addr(), pixMap.rowBytes() }; 257 258 return resourceProvider->createTexture(desc, budgeted, fit, mipLevel); 259 }, desc, GrMipMapped::kNo, renderTargetFlags, fit, budgeted); 260 261 if (fResourceProvider) { 262 // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however 263 // we're better off instantiating the proxy immediately here. 264 if (!proxy->priv().doLazyInstantiation(fResourceProvider)) { 265 return nullptr; 266 } 267 } 268 return proxy; 269 } 270 271 sk_sp<GrTextureProxy> GrProxyProvider::createMipMapProxy(const GrSurfaceDesc& desc, 272 SkBudgeted budgeted) { 273 ASSERT_SINGLE_OWNER 274 275 if (this->isAbandoned()) { 276 return nullptr; 277 } 278 279 return this->createProxy(desc, GrMipMapped::kYes, SkBackingFit::kExact, budgeted, 0); 280 } 281 282 sk_sp<GrTextureProxy> GrProxyProvider::createMipMapProxyFromBitmap(const SkBitmap& bitmap, 283 SkColorSpace* dstColorSpace) { 284 SkDestinationSurfaceColorMode mipColorMode = dstColorSpace 285 ? SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware 286 : SkDestinationSurfaceColorMode::kLegacy; 287 288 if (!SkImageInfoIsValid(bitmap.info(), mipColorMode)) { 289 return nullptr; 290 } 291 292 SkPixmap pixmap; 293 if (!bitmap.peekPixels(&pixmap)) { 294 return nullptr; 295 } 296 297 ATRACE_ANDROID_FRAMEWORK("Upload MipMap Texture [%ux%u]", pixmap.width(), pixmap.height()); 298 sk_sp<SkMipMap> mipmaps(SkMipMap::Build(pixmap, mipColorMode, nullptr)); 299 if (!mipmaps) { 300 return nullptr; 301 } 302 303 if (mipmaps->countLevels() < 0) { 304 return nullptr; 305 } 306 307 // In non-ddl we will always instantiate right away. Thus we never want to copy the SkBitmap 308 // even if its mutable. In ddl, if the bitmap is mutable then we must make a copy since the 309 // upload of the data to the gpu can happen at anytime and the bitmap may change by then. 310 SkCopyPixelsMode copyMode = this->mutableBitmapsNeedCopy() ? kIfMutable_SkCopyPixelsMode 311 : kNever_SkCopyPixelsMode; 312 sk_sp<SkImage> baseLevel = SkMakeImageFromRasterBitmap(bitmap, copyMode); 313 314 if (!baseLevel) { 315 return nullptr; 316 } 317 318 GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(pixmap.info(), *this->caps()); 319 320 if (0 == mipmaps->countLevels()) { 321 return this->createTextureProxy(baseLevel, kNone_GrSurfaceFlags, kTopLeft_GrSurfaceOrigin, 322 1, SkBudgeted::kYes, SkBackingFit::kExact); 323 324 } 325 326 sk_sp<GrTextureProxy> proxy = this->createLazyProxy( 327 [desc, baseLevel, mipmaps, mipColorMode] 328 (GrResourceProvider* resourceProvider) { 329 if (!resourceProvider) { 330 return sk_sp<GrTexture>(); 331 } 332 333 const int mipLevelCount = mipmaps->countLevels() + 1; 334 std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]); 335 336 SkPixmap pixmap; 337 SkAssertResult(baseLevel->peekPixels(&pixmap)); 338 339 // DDL TODO: Instead of copying all this info into GrMipLevels we should just plumb 340 // the use of SkMipMap down through Ganesh. 341 texels[0].fPixels = pixmap.addr(); 342 texels[0].fRowBytes = pixmap.rowBytes(); 343 344 for (int i = 1; i < mipLevelCount; ++i) { 345 SkMipMap::Level generatedMipLevel; 346 mipmaps->getLevel(i - 1, &generatedMipLevel); 347 texels[i].fPixels = generatedMipLevel.fPixmap.addr(); 348 texels[i].fRowBytes = generatedMipLevel.fPixmap.rowBytes(); 349 SkASSERT(texels[i].fPixels); 350 } 351 352 return resourceProvider->createTexture(desc, SkBudgeted::kYes, texels.get(), 353 mipLevelCount, mipColorMode); 354 }, desc, GrMipMapped::kYes, SkBackingFit::kExact, SkBudgeted::kYes); 355 356 if (fResourceProvider) { 357 // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however 358 // we're better off instantiating the proxy immediately here. 359 if (!proxy->priv().doLazyInstantiation(fResourceProvider)) { 360 return nullptr; 361 } 362 } 363 return proxy; 364 } 365 366 sk_sp<GrTextureProxy> GrProxyProvider::createProxy(const GrSurfaceDesc& desc, 367 GrMipMapped mipMapped, 368 SkBackingFit fit, 369 SkBudgeted budgeted, 370 uint32_t flags) { 371 SkASSERT(0 == flags || GrResourceProvider::kNoPendingIO_Flag == flags); 372 373 if (GrMipMapped::kYes == mipMapped) { 374 // SkMipMap doesn't include the base level in the level count so we have to add 1 375 int mipCount = SkMipMap::ComputeLevelCount(desc.fWidth, desc.fHeight) + 1; 376 if (1 == mipCount) { 377 mipMapped = GrMipMapped::kNo; 378 } 379 } 380 381 if (!this->caps()->validateSurfaceDesc(desc, mipMapped)) { 382 return nullptr; 383 } 384 GrSurfaceDesc copyDesc = desc; 385 if (desc.fFlags & kRenderTarget_GrSurfaceFlag) { 386 copyDesc.fSampleCnt = 387 this->caps()->getRenderTargetSampleCount(desc.fSampleCnt, desc.fConfig); 388 } 389 390 if (copyDesc.fFlags & kRenderTarget_GrSurfaceFlag) { 391 // We know anything we instantiate later from this deferred path will be 392 // both texturable and renderable 393 return sk_sp<GrTextureProxy>( 394 new GrTextureRenderTargetProxy(*this->caps(), copyDesc, mipMapped, fit, budgeted, 395 flags)); 396 } 397 398 return sk_sp<GrTextureProxy>(new GrTextureProxy(copyDesc, mipMapped, fit, budgeted, nullptr, 0, 399 flags)); 400 } 401 402 sk_sp<GrTextureProxy> GrProxyProvider::createWrappedTextureProxy( 403 const GrBackendTexture& backendTex, 404 GrSurfaceOrigin origin, 405 GrWrapOwnership ownership, 406 ReleaseProc releaseProc, 407 ReleaseContext releaseCtx) { 408 if (this->isAbandoned()) { 409 return nullptr; 410 } 411 412 GrSurfaceDesc desc; 413 desc.fOrigin = origin; 414 desc.fWidth = backendTex.width(); 415 desc.fHeight = backendTex.height(); 416 desc.fConfig = backendTex.config(); 417 GrMipMapped mipMapped = backendTex.hasMipMaps() ? GrMipMapped::kYes : GrMipMapped::kNo; 418 419 sk_sp<GrReleaseProcHelper> releaseHelper; 420 if (releaseProc) { 421 releaseHelper.reset(new GrReleaseProcHelper(releaseProc, releaseCtx)); 422 } 423 424 sk_sp<GrTextureProxy> proxy = this->createLazyProxy( 425 [backendTex, ownership, releaseHelper] 426 (GrResourceProvider* resourceProvider) { 427 if (!resourceProvider) { 428 // If this had a releaseHelper it will get unrefed when we delete this lambda 429 // and will call the release proc so that the client knows they can free the 430 // underlying backend object. 431 return sk_sp<GrTexture>(); 432 } 433 434 sk_sp<GrTexture> tex = resourceProvider->wrapBackendTexture(backendTex, 435 ownership); 436 if (!tex) { 437 return sk_sp<GrTexture>(); 438 } 439 if (releaseHelper) { 440 // This gives the texture a ref on the releaseHelper 441 tex->setRelease(releaseHelper); 442 } 443 SkASSERT(!tex->asRenderTarget()); // Strictly a GrTexture 444 // Make sure we match how we created the proxy with SkBudgeted::kNo 445 SkASSERT(SkBudgeted::kNo == tex->resourcePriv().isBudgeted()); 446 447 return tex; 448 }, desc, mipMapped, SkBackingFit::kExact, SkBudgeted::kNo); 449 450 if (fResourceProvider) { 451 // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however, 452 // we're better off instantiating the proxy immediately here. 453 if (!proxy->priv().doLazyInstantiation(fResourceProvider)) { 454 return nullptr; 455 } 456 } 457 return proxy; 458 } 459 460 sk_sp<GrTextureProxy> GrProxyProvider::createWrappedTextureProxy(const GrBackendTexture& backendTex, 461 GrSurfaceOrigin origin, 462 int sampleCnt) { 463 if (this->isAbandoned()) { 464 return nullptr; 465 } 466 467 sampleCnt = this->caps()->getRenderTargetSampleCount(sampleCnt, backendTex.config()); 468 if (!sampleCnt) { 469 return nullptr; 470 } 471 472 GrSurfaceDesc desc; 473 desc.fOrigin = origin; 474 desc.fWidth = backendTex.width(); 475 desc.fHeight = backendTex.height(); 476 desc.fConfig = backendTex.config(); 477 desc.fFlags = kRenderTarget_GrSurfaceFlag; 478 desc.fSampleCnt = sampleCnt; 479 GrMipMapped mipMapped = backendTex.hasMipMaps() ? GrMipMapped::kYes : GrMipMapped::kNo; 480 481 GrRenderTargetFlags renderTargetFlags = GrRenderTargetFlags::kNone; 482 if (fCaps->usesMixedSamples() && sampleCnt > 1) { 483 renderTargetFlags |= GrRenderTargetFlags::kMixedSampled; 484 } 485 if (fCaps->maxWindowRectangles() > 0) { 486 renderTargetFlags |= GrRenderTargetFlags::kWindowRectsSupport; 487 } 488 489 sk_sp<GrTextureProxy> proxy = this->createLazyProxy( 490 [backendTex, sampleCnt] (GrResourceProvider* resourceProvider) { 491 if (!resourceProvider) { 492 return sk_sp<GrTexture>(); 493 } 494 495 sk_sp<GrTexture> tex = resourceProvider->wrapRenderableBackendTexture(backendTex, 496 sampleCnt); 497 if (!tex) { 498 return sk_sp<GrTexture>(); 499 } 500 SkASSERT(tex->asRenderTarget()); // A GrTextureRenderTarget 501 // Make sure we match how we created the proxy with SkBudgeted::kNo 502 SkASSERT(SkBudgeted::kNo == tex->resourcePriv().isBudgeted()); 503 504 return tex; 505 }, desc, mipMapped, renderTargetFlags, SkBackingFit::kExact, SkBudgeted::kNo); 506 507 if (fResourceProvider) { 508 // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however, 509 // we're better off instantiating the proxy immediately here. 510 if (!proxy->priv().doLazyInstantiation(fResourceProvider)) { 511 return nullptr; 512 } 513 } 514 return proxy; 515 } 516 517 sk_sp<GrSurfaceProxy> GrProxyProvider::createWrappedRenderTargetProxy( 518 const GrBackendRenderTarget& backendRT, 519 GrSurfaceOrigin origin) { 520 if (this->isAbandoned()) { 521 return nullptr; 522 } 523 524 GrSurfaceDesc desc; 525 desc.fOrigin = origin; 526 desc.fWidth = backendRT.width(); 527 desc.fHeight = backendRT.height(); 528 desc.fConfig = backendRT.config(); 529 desc.fFlags = kRenderTarget_GrSurfaceFlag; 530 desc.fSampleCnt = backendRT.sampleCnt(); 531 532 GrRenderTargetFlags renderTargetFlags = GrRenderTargetFlags::kNone; 533 if (fCaps->isMixedSamplesSupportedForRT(backendRT) && backendRT.sampleCnt() > 1) { 534 renderTargetFlags |= GrRenderTargetFlags::kMixedSampled; 535 } 536 if (fCaps->isWindowRectanglesSupportedForRT(backendRT)) { 537 renderTargetFlags |= GrRenderTargetFlags::kWindowRectsSupport; 538 } 539 540 sk_sp<GrRenderTargetProxy> proxy = this->createLazyRenderTargetProxy( 541 [backendRT] (GrResourceProvider* resourceProvider) { 542 if (!resourceProvider) { 543 return sk_sp<GrRenderTarget>(); 544 } 545 546 sk_sp<GrRenderTarget> rt = resourceProvider->wrapBackendRenderTarget(backendRT); 547 if (!rt) { 548 return sk_sp<GrRenderTarget>(); 549 } 550 SkASSERT(!rt->asTexture()); // A GrRenderTarget that's not textureable 551 SkASSERT(!rt->getUniqueKey().isValid()); 552 // Make sure we match how we created the proxy with SkBudgeted::kNo 553 SkASSERT(SkBudgeted::kNo == rt->resourcePriv().isBudgeted()); 554 555 return rt; 556 }, desc, renderTargetFlags, Textureable::kNo, GrMipMapped::kNo, SkBackingFit::kExact, 557 SkBudgeted::kNo); 558 559 if (fResourceProvider) { 560 // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however, 561 // we're better off instantiating the proxy immediately here. 562 if (!proxy->priv().doLazyInstantiation(fResourceProvider)) { 563 return nullptr; 564 } 565 } 566 return proxy; 567 } 568 569 sk_sp<GrSurfaceProxy> GrProxyProvider::createWrappedRenderTargetProxy( 570 const GrBackendTexture& backendTex, 571 GrSurfaceOrigin origin, 572 int sampleCnt) { 573 if (this->isAbandoned()) { 574 return nullptr; 575 } 576 577 sampleCnt = this->caps()->getRenderTargetSampleCount(sampleCnt, backendTex.config()); 578 if (!sampleCnt) { 579 return nullptr; 580 } 581 582 GrSurfaceDesc desc; 583 desc.fOrigin = origin; 584 desc.fWidth = backendTex.width(); 585 desc.fHeight = backendTex.height(); 586 desc.fConfig = backendTex.config(); 587 desc.fFlags = kRenderTarget_GrSurfaceFlag; 588 desc.fSampleCnt = sampleCnt; 589 590 GrRenderTargetFlags renderTargetFlags = GrRenderTargetFlags::kNone; 591 if (fCaps->usesMixedSamples() && sampleCnt > 1) { 592 renderTargetFlags |= GrRenderTargetFlags::kMixedSampled; 593 } 594 if (fCaps->maxWindowRectangles() > 0) { 595 renderTargetFlags |= GrRenderTargetFlags::kWindowRectsSupport; 596 } 597 598 sk_sp<GrRenderTargetProxy> proxy = this->createLazyRenderTargetProxy( 599 [backendTex, sampleCnt] (GrResourceProvider* resourceProvider) { 600 if (!resourceProvider) { 601 return sk_sp<GrRenderTarget>(); 602 } 603 604 sk_sp<GrRenderTarget> rt = resourceProvider->wrapBackendTextureAsRenderTarget( 605 backendTex, sampleCnt); 606 if (!rt) { 607 return sk_sp<GrRenderTarget>(); 608 } 609 SkASSERT(!rt->asTexture()); // A GrRenderTarget that's not textureable 610 SkASSERT(!rt->getUniqueKey().isValid()); 611 // Make sure we match how we created the proxy with SkBudgeted::kNo 612 SkASSERT(SkBudgeted::kNo == rt->resourcePriv().isBudgeted()); 613 614 return rt; 615 }, desc, renderTargetFlags, Textureable::kNo, GrMipMapped::kNo, SkBackingFit::kExact, 616 SkBudgeted::kNo); 617 618 if (fResourceProvider) { 619 // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however, 620 // we're better off instantiating the proxy immediately here. 621 if (!proxy->priv().doLazyInstantiation(fResourceProvider)) { 622 return nullptr; 623 } 624 } 625 return proxy; 626 } 627 628 sk_sp<GrTextureProxy> GrProxyProvider::createLazyProxy(LazyInstantiateCallback&& callback, 629 const GrSurfaceDesc& desc, 630 GrMipMapped mipMapped, 631 SkBackingFit fit, SkBudgeted budgeted) { 632 return this->createLazyProxy(std::move(callback), desc, mipMapped, GrRenderTargetFlags::kNone, 633 fit, budgeted); 634 } 635 636 sk_sp<GrTextureProxy> GrProxyProvider::createLazyProxy(LazyInstantiateCallback&& callback, 637 const GrSurfaceDesc& desc, 638 GrMipMapped mipMapped, 639 GrRenderTargetFlags renderTargetFlags, 640 SkBackingFit fit, SkBudgeted budgeted) { 641 SkASSERT((desc.fWidth <= 0 && desc.fHeight <= 0) || 642 (desc.fWidth > 0 && desc.fHeight > 0)); 643 uint32_t flags = GrResourceProvider::kNoPendingIO_Flag; 644 645 #ifdef SK_DEBUG 646 if (SkToBool(kRenderTarget_GrSurfaceFlag & desc.fFlags)) { 647 if (SkToBool(renderTargetFlags & GrRenderTargetFlags::kMixedSampled)) { 648 SkASSERT(fCaps->usesMixedSamples() && desc.fSampleCnt > 1); 649 } 650 if (SkToBool(renderTargetFlags & GrRenderTargetFlags::kWindowRectsSupport)) { 651 SkASSERT(fCaps->maxWindowRectangles() > 0); 652 } 653 } 654 #endif 655 656 using LazyInstantiationType = GrSurfaceProxy::LazyInstantiationType; 657 // For non-ddl draws always make lazy proxy's single use. 658 LazyInstantiationType lazyType = fResourceProvider ? LazyInstantiationType::kSingleUse 659 : LazyInstantiationType::kMultipleUse; 660 661 return sk_sp<GrTextureProxy>(SkToBool(kRenderTarget_GrSurfaceFlag & desc.fFlags) ? 662 new GrTextureRenderTargetProxy(std::move(callback), lazyType, desc, 663 mipMapped, fit, budgeted, flags, 664 renderTargetFlags) : 665 new GrTextureProxy(std::move(callback), lazyType, desc, mipMapped, 666 fit, budgeted, flags)); 667 } 668 669 sk_sp<GrRenderTargetProxy> GrProxyProvider::createLazyRenderTargetProxy( 670 LazyInstantiateCallback&& callback, 671 const GrSurfaceDesc& desc, 672 GrRenderTargetFlags renderTargetFlags, 673 Textureable textureable, 674 GrMipMapped mipMapped, 675 SkBackingFit fit, SkBudgeted budgeted) { 676 SkASSERT((desc.fWidth <= 0 && desc.fHeight <= 0) || 677 (desc.fWidth > 0 && desc.fHeight > 0)); 678 SkASSERT(SkToBool(kRenderTarget_GrSurfaceFlag & desc.fFlags)); 679 uint32_t flags = GrResourceProvider::kNoPendingIO_Flag; 680 681 #ifdef SK_DEBUG 682 if (SkToBool(renderTargetFlags & GrRenderTargetFlags::kMixedSampled)) { 683 SkASSERT(fCaps->usesMixedSamples() && desc.fSampleCnt > 1); 684 } 685 if (SkToBool(renderTargetFlags & GrRenderTargetFlags::kWindowRectsSupport)) { 686 SkASSERT(fCaps->maxWindowRectangles() > 0); 687 } 688 #endif 689 690 using LazyInstantiationType = GrSurfaceProxy::LazyInstantiationType; 691 // For non-ddl draws always make lazy proxy's single use. 692 LazyInstantiationType lazyType = fResourceProvider ? LazyInstantiationType::kSingleUse 693 : LazyInstantiationType::kMultipleUse; 694 695 if (Textureable::kYes == textureable) { 696 return sk_sp<GrRenderTargetProxy>(new GrTextureRenderTargetProxy(std::move(callback), 697 lazyType, desc, mipMapped, 698 fit, budgeted, flags, 699 renderTargetFlags)); 700 } 701 702 return sk_sp<GrRenderTargetProxy>(new GrRenderTargetProxy(std::move(callback), lazyType, desc, 703 fit, budgeted, flags, 704 renderTargetFlags)); 705 } 706 707 sk_sp<GrTextureProxy> GrProxyProvider::createFullyLazyProxy(LazyInstantiateCallback&& callback, 708 Renderable renderable, 709 GrSurfaceOrigin origin, 710 GrPixelConfig config) { 711 GrSurfaceDesc desc; 712 GrRenderTargetFlags renderTargetFlags = GrRenderTargetFlags::kNone; 713 if (Renderable::kYes == renderable) { 714 desc.fFlags = kRenderTarget_GrSurfaceFlag; 715 if (fCaps->maxWindowRectangles() > 0) { 716 renderTargetFlags |= GrRenderTargetFlags::kWindowRectsSupport; 717 } 718 } 719 desc.fOrigin = origin; 720 desc.fWidth = -1; 721 desc.fHeight = -1; 722 desc.fConfig = config; 723 desc.fSampleCnt = 1; 724 725 return this->createLazyProxy(std::move(callback), desc, GrMipMapped::kNo, renderTargetFlags, 726 SkBackingFit::kApprox, SkBudgeted::kYes); 727 728 } 729 730 bool GrProxyProvider::IsFunctionallyExact(GrSurfaceProxy* proxy) { 731 return proxy->priv().isExact() || (SkIsPow2(proxy->width()) && SkIsPow2(proxy->height())); 732 } 733 734 void GrProxyProvider::processInvalidProxyUniqueKey(const GrUniqueKey& key) { 735 // Note: this method is called for the whole variety of GrGpuResources so often 'key' 736 // will not be in 'fUniquelyKeyedProxies'. 737 GrTextureProxy* proxy = fUniquelyKeyedProxies.find(key); 738 if (proxy) { 739 this->processInvalidProxyUniqueKey(key, proxy, false); 740 } 741 } 742 743 void GrProxyProvider::processInvalidProxyUniqueKey(const GrUniqueKey& key, GrTextureProxy* proxy, 744 bool invalidateSurface) { 745 SkASSERT(proxy); 746 SkASSERT(proxy->getUniqueKey().isValid()); 747 SkASSERT(proxy->getUniqueKey() == key); 748 749 fUniquelyKeyedProxies.remove(key); 750 proxy->cacheAccess().clearUniqueKey(); 751 752 if (invalidateSurface && proxy->priv().isInstantiated()) { 753 GrSurface* surface = proxy->priv().peekSurface(); 754 if (surface) { 755 surface->resourcePriv().removeUniqueKey(); 756 } 757 } 758 } 759 760 void GrProxyProvider::removeAllUniqueKeys() { 761 UniquelyKeyedProxyHash::Iter iter(&fUniquelyKeyedProxies); 762 for (UniquelyKeyedProxyHash::Iter iter(&fUniquelyKeyedProxies); !iter.done(); ++iter) { 763 GrTextureProxy& tmp = *iter; 764 765 this->processInvalidProxyUniqueKey(tmp.getUniqueKey(), &tmp, false); 766 } 767 SkASSERT(!fUniquelyKeyedProxies.count()); 768 } 769