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 "src/gpu/GrProxyProvider.h" 9 10#include "include/core/SkBitmap.h" 11#include "include/core/SkImage.h" 12#include "include/gpu/GrDirectContext.h" 13#include "include/private/GrImageContext.h" 14#include "include/private/GrResourceKey.h" 15#include "include/private/GrSingleOwner.h" 16#include "include/private/SkImageInfoPriv.h" 17#include "src/core/SkAutoPixmapStorage.h" 18#include "src/core/SkCompressedDataUtils.h" 19#include "src/core/SkImagePriv.h" 20#include "src/core/SkMipmap.h" 21#include "src/core/SkTraceEvent.h" 22#include "src/gpu/GrCaps.h" 23#include "src/gpu/GrContextThreadSafeProxyPriv.h" 24#include "src/gpu/GrDirectContextPriv.h" 25#include "src/gpu/GrImageContextPriv.h" 26#include "src/gpu/GrRenderTarget.h" 27#include "src/gpu/GrResourceProvider.h" 28#include "src/gpu/GrSurfaceProxy.h" 29#include "src/gpu/GrSurfaceProxyPriv.h" 30#include "src/gpu/GrTexture.h" 31#include "src/gpu/GrTextureProxyCacheAccess.h" 32#include "src/gpu/GrTextureRenderTargetProxy.h" 33#include "src/gpu/SkGr.h" 34#include "src/image/SkImage_Base.h" 35 36#ifdef SK_VULKAN 37#include "include/gpu/vk/GrVkTypes.h" 38#endif 39 40#define ASSERT_SINGLE_OWNER GR_ASSERT_SINGLE_OWNER(fImageContext->priv().singleOwner()) 41 42GrProxyProvider::GrProxyProvider(GrImageContext* imageContext) : fImageContext(imageContext) {} 43 44GrProxyProvider::~GrProxyProvider() { 45 if (this->renderingDirectly()) { 46 // In DDL-mode a proxy provider can still have extant uniquely keyed proxies (since 47 // they need their unique keys to, potentially, find a cached resource when the 48 // DDL is played) but, in non-DDL-mode they should all have been cleaned up by this point. 49 SkASSERT(!fUniquelyKeyedProxies.count()); 50 } 51} 52 53bool GrProxyProvider::assignUniqueKeyToProxy(const GrUniqueKey& key, GrTextureProxy* proxy) { 54 ASSERT_SINGLE_OWNER 55 SkASSERT(key.isValid()); 56 if (this->isAbandoned() || !proxy) { 57 return false; 58 } 59 60 // Only the proxyProvider that created a proxy should be assigning unique keys to it. 61 SkASSERT(this->isDDLProvider() == proxy->creatingProvider()); 62 63#ifdef SK_DEBUG 64 { 65 auto direct = fImageContext->asDirectContext(); 66 if (direct) { 67 GrResourceCache* resourceCache = direct->priv().getResourceCache(); 68 // If there is already a GrResource with this key then the caller has violated the 69 // normal usage pattern of uniquely keyed resources (e.g., they have created one w/o 70 // first seeing if it already existed in the cache). 71 SkASSERT(!resourceCache->findAndRefUniqueResource(key)); 72 } 73 } 74#endif 75 76 SkASSERT(!fUniquelyKeyedProxies.find(key)); // multiple proxies can't get the same key 77 78 proxy->cacheAccess().setUniqueKey(this, key); 79 SkASSERT(proxy->getUniqueKey() == key); 80 fUniquelyKeyedProxies.add(proxy); 81 return true; 82} 83 84template <class T> 85sk_sp<T> GrProxyProvider::assignTagToProxy(sk_sp<T> proxy) { 86 if (!proxy) { 87 return proxy; 88 } 89 auto direct = fImageContext->priv().asDirectContext(); 90 if (direct) { 91 proxy->setGrProxyTag(direct->getCurrentGrResourceTag()); 92 } 93 return proxy; 94} 95 96void GrProxyProvider::adoptUniqueKeyFromSurface(GrTextureProxy* proxy, const GrSurface* surf) { 97 SkASSERT(surf->getUniqueKey().isValid()); 98 proxy->cacheAccess().setUniqueKey(this, surf->getUniqueKey()); 99 SkASSERT(proxy->getUniqueKey() == surf->getUniqueKey()); 100 // multiple proxies can't get the same key 101 SkASSERT(!fUniquelyKeyedProxies.find(surf->getUniqueKey())); 102 fUniquelyKeyedProxies.add(proxy); 103} 104 105void GrProxyProvider::removeUniqueKeyFromProxy(GrTextureProxy* proxy) { 106 ASSERT_SINGLE_OWNER 107 SkASSERT(proxy); 108 SkASSERT(proxy->getUniqueKey().isValid()); 109 110 if (this->isAbandoned()) { 111 return; 112 } 113 114 this->processInvalidUniqueKey(proxy->getUniqueKey(), proxy, InvalidateGPUResource::kYes); 115} 116 117sk_sp<GrTextureProxy> GrProxyProvider::findProxyByUniqueKey(const GrUniqueKey& key) { 118 ASSERT_SINGLE_OWNER 119 120 if (this->isAbandoned()) { 121 return nullptr; 122 } 123 124 GrTextureProxy* proxy = fUniquelyKeyedProxies.find(key); 125 if (proxy) { 126 return sk_ref_sp(proxy); 127 } 128 return nullptr; 129} 130 131/////////////////////////////////////////////////////////////////////////////// 132 133#if GR_TEST_UTILS 134sk_sp<GrTextureProxy> GrProxyProvider::testingOnly_createInstantiatedProxy( 135 SkISize dimensions, 136 const GrBackendFormat& format, 137 GrRenderable renderable, 138 int renderTargetSampleCnt, 139 SkBackingFit fit, 140 SkBudgeted budgeted, 141 GrProtected isProtected) { 142 ASSERT_SINGLE_OWNER 143 if (this->isAbandoned()) { 144 return nullptr; 145 } 146 auto direct = fImageContext->asDirectContext(); 147 if (!direct) { 148 return nullptr; 149 } 150 151 if (this->caps()->isFormatCompressed(format)) { 152 // TODO: Allow this to go to GrResourceProvider::createCompressedTexture() once we no longer 153 // rely on GrColorType to get a swizzle for the proxy. 154 return nullptr; 155 } 156 157 GrResourceProvider* resourceProvider = direct->priv().resourceProvider(); 158 sk_sp<GrTexture> tex; 159 160 if (SkBackingFit::kApprox == fit) { 161 tex = resourceProvider->createApproxTexture(dimensions, 162 format, 163 format.textureType(), 164 renderable, 165 renderTargetSampleCnt, 166 isProtected); 167 } else { 168 tex = resourceProvider->createTexture(dimensions, 169 format, 170 format.textureType(), 171 renderable, 172 renderTargetSampleCnt, 173 GrMipmapped::kNo, 174 budgeted, 175 isProtected); 176 } 177 if (!tex) { 178 return nullptr; 179 } 180 181 return this->createWrapped(std::move(tex), UseAllocator::kYes); 182} 183 184sk_sp<GrTextureProxy> GrProxyProvider::testingOnly_createInstantiatedProxy( 185 SkISize dimensions, 186 GrColorType colorType, 187 GrRenderable renderable, 188 int renderTargetSampleCnt, 189 SkBackingFit fit, 190 SkBudgeted budgeted, 191 GrProtected isProtected) { 192 ASSERT_SINGLE_OWNER 193 if (this->isAbandoned()) { 194 return nullptr; 195 } 196 auto format = this->caps()->getDefaultBackendFormat(colorType, renderable); 197 return this->testingOnly_createInstantiatedProxy(dimensions, 198 format, 199 renderable, 200 renderTargetSampleCnt, 201 fit, 202 budgeted, 203 isProtected); 204} 205 206sk_sp<GrTextureProxy> GrProxyProvider::testingOnly_createWrapped(sk_sp<GrTexture> tex) { 207 return this->createWrapped(std::move(tex), UseAllocator::kYes); 208} 209#endif 210 211sk_sp<GrTextureProxy> GrProxyProvider::createWrapped(sk_sp<GrTexture> tex, 212 UseAllocator useAllocator) { 213#ifdef SK_DEBUG 214 if (tex->getUniqueKey().isValid()) { 215 SkASSERT(!this->findProxyByUniqueKey(tex->getUniqueKey())); 216 } 217#endif 218 219 if (tex->asRenderTarget()) { 220 return assignTagToProxy( 221 sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(std::move(tex), useAllocator, this->isDDLProvider()))); 222 } else { 223 return assignTagToProxy( 224 sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(tex), useAllocator, 225 this->isDDLProvider()))); 226 } 227} 228 229sk_sp<GrTextureProxy> GrProxyProvider::findOrCreateProxyByUniqueKey(const GrUniqueKey& key, 230 UseAllocator useAllocator) { 231 ASSERT_SINGLE_OWNER 232 233 if (this->isAbandoned()) { 234 return nullptr; 235 } 236 237 sk_sp<GrTextureProxy> result = this->findProxyByUniqueKey(key); 238 if (result) { 239 return result; 240 } 241 242 auto direct = fImageContext->asDirectContext(); 243 if (!direct) { 244 return nullptr; 245 } 246 247 GrResourceCache* resourceCache = direct->priv().getResourceCache(); 248 249 GrGpuResource* resource = resourceCache->findAndRefUniqueResource(key); 250 if (!resource) { 251 return nullptr; 252 } 253 254 sk_sp<GrTexture> texture(static_cast<GrSurface*>(resource)->asTexture()); 255 SkASSERT(texture); 256 257 result = this->createWrapped(std::move(texture), useAllocator); 258 SkASSERT(result->getUniqueKey() == key); 259 // createWrapped should've added this for us 260 SkASSERT(fUniquelyKeyedProxies.find(key)); 261 return result; 262} 263 264GrSurfaceProxyView GrProxyProvider::findCachedProxyWithColorTypeFallback(const GrUniqueKey& key, 265 GrSurfaceOrigin origin, 266 GrColorType ct, 267 int sampleCnt) { 268 auto proxy = this->findOrCreateProxyByUniqueKey(key); 269 if (!proxy) { 270 return {}; 271 } 272 const GrCaps* caps = fImageContext->priv().caps(); 273 274 // Assume that we used a fallback color type if and only if the proxy is renderable. 275 if (proxy->asRenderTargetProxy()) { 276 GrBackendFormat expectedFormat; 277 std::tie(ct, expectedFormat) = caps->getFallbackColorTypeAndFormat(ct, sampleCnt); 278 SkASSERT(expectedFormat == proxy->backendFormat()); 279 } 280 GrSwizzle swizzle = caps->getReadSwizzle(proxy->backendFormat(), ct); 281 return {std::move(proxy), origin, swizzle}; 282} 283 284sk_sp<GrTextureProxy> GrProxyProvider::createProxyFromBitmap(const SkBitmap& bitmap, 285 GrMipmapped mipMapped, 286 SkBackingFit fit, 287 SkBudgeted budgeted) { 288 ASSERT_SINGLE_OWNER 289 SkASSERT(fit == SkBackingFit::kExact || mipMapped == GrMipmapped::kNo); 290 291 if (this->isAbandoned()) { 292 return nullptr; 293 } 294 295 if (!SkImageInfoIsValid(bitmap.info())) { 296 return nullptr; 297 } 298 299 ATRACE_ANDROID_FRAMEWORK("Upload %sTexture [%ux%u]", 300 GrMipmapped::kYes == mipMapped ? "MipMap " : "", 301 bitmap.width(), bitmap.height()); 302 303 // In non-ddl we will always instantiate right away. Thus we never want to copy the SkBitmap 304 // even if its mutable. In ddl, if the bitmap is mutable then we must make a copy since the 305 // upload of the data to the gpu can happen at anytime and the bitmap may change by then. 306 SkBitmap copyBitmap = bitmap; 307 if (!this->renderingDirectly() && !bitmap.isImmutable()) { 308 copyBitmap.allocPixels(); 309 if (!bitmap.readPixels(copyBitmap.pixmap())) { 310 return nullptr; 311 } 312 copyBitmap.setImmutable(); 313 } 314 315 sk_sp<GrTextureProxy> proxy; 316 if (mipMapped == GrMipmapped::kNo || 317 0 == SkMipmap::ComputeLevelCount(copyBitmap.width(), copyBitmap.height())) { 318 proxy = this->createNonMippedProxyFromBitmap(copyBitmap, fit, budgeted); 319 } else { 320 proxy = this->createMippedProxyFromBitmap(copyBitmap, budgeted); 321 } 322 323 if (!proxy) { 324 return nullptr; 325 } 326 327 auto direct = fImageContext->asDirectContext(); 328 if (direct) { 329 GrResourceProvider* resourceProvider = direct->priv().resourceProvider(); 330 331 // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however 332 // we're better off instantiating the proxy immediately here. 333 if (!proxy->priv().doLazyInstantiation(resourceProvider)) { 334 return nullptr; 335 } 336 } 337 return assignTagToProxy(proxy); 338} 339 340sk_sp<GrTextureProxy> GrProxyProvider::createNonMippedProxyFromBitmap(const SkBitmap& bitmap, 341 SkBackingFit fit, 342 SkBudgeted budgeted) { 343 auto dims = bitmap.dimensions(); 344 345 auto colorType = SkColorTypeToGrColorType(bitmap.colorType()); 346 GrBackendFormat format = this->caps()->getDefaultBackendFormat(colorType, GrRenderable::kNo); 347 if (!format.isValid()) { 348 return nullptr; 349 } 350 351 sk_sp<GrTextureProxy> proxy = this->createLazyProxy( 352 [bitmap](GrResourceProvider* resourceProvider, const LazySurfaceDesc& desc) { 353 SkASSERT(desc.fMipmapped == GrMipmapped::kNo); 354 GrMipLevel mipLevel = {bitmap.getPixels(), bitmap.rowBytes(), nullptr}; 355 auto colorType = SkColorTypeToGrColorType(bitmap.colorType()); 356 return LazyCallbackResult(resourceProvider->createTexture( 357 desc.fDimensions, 358 desc.fFormat, 359 desc.fTextureType, 360 colorType, 361 desc.fRenderable, 362 desc.fSampleCnt, 363 desc.fBudgeted, 364 desc.fFit, 365 desc.fProtected, 366 mipLevel)); 367 }, 368 format, dims, GrMipmapped::kNo, GrMipmapStatus::kNotAllocated, 369 GrInternalSurfaceFlags::kNone, fit, budgeted, GrProtected::kNo, UseAllocator::kYes); 370 371 if (!proxy) { 372 return nullptr; 373 } 374 SkASSERT(proxy->dimensions() == bitmap.dimensions()); 375 return proxy; 376} 377 378sk_sp<GrTextureProxy> GrProxyProvider::createMippedProxyFromBitmap(const SkBitmap& bitmap, 379 SkBudgeted budgeted) { 380 SkASSERT(this->caps()->mipmapSupport()); 381 382 auto colorType = SkColorTypeToGrColorType(bitmap.colorType()); 383 GrBackendFormat format = this->caps()->getDefaultBackendFormat(colorType, GrRenderable::kNo); 384 if (!format.isValid()) { 385 return nullptr; 386 } 387 388 sk_sp<SkMipmap> mipmaps(SkMipmap::Build(bitmap.pixmap(), nullptr)); 389 if (!mipmaps) { 390 return nullptr; 391 } 392 393 auto dims = bitmap.dimensions(); 394 395 sk_sp<GrTextureProxy> proxy = this->createLazyProxy( 396 [bitmap, mipmaps](GrResourceProvider* resourceProvider, const LazySurfaceDesc& desc) { 397 const int mipLevelCount = mipmaps->countLevels() + 1; 398 std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]); 399 auto colorType = SkColorTypeToGrColorType(bitmap.colorType()); 400 401 texels[0].fPixels = bitmap.getPixels(); 402 texels[0].fRowBytes = bitmap.rowBytes(); 403 404 for (int i = 1; i < mipLevelCount; ++i) { 405 SkMipmap::Level generatedMipLevel; 406 mipmaps->getLevel(i - 1, &generatedMipLevel); 407 texels[i].fPixels = generatedMipLevel.fPixmap.addr(); 408 texels[i].fRowBytes = generatedMipLevel.fPixmap.rowBytes(); 409 SkASSERT(texels[i].fPixels); 410 SkASSERT(generatedMipLevel.fPixmap.colorType() == bitmap.colorType()); 411 } 412 return LazyCallbackResult(resourceProvider->createTexture( 413 desc.fDimensions, 414 desc.fFormat, 415 desc.fTextureType, 416 colorType, 417 GrRenderable::kNo, 418 1, 419 desc.fBudgeted, 420 GrMipMapped::kYes, 421 GrProtected::kNo, 422 texels.get())); 423 }, 424 format, dims, GrMipmapped::kYes, GrMipmapStatus::kValid, GrInternalSurfaceFlags::kNone, 425 SkBackingFit::kExact, budgeted, GrProtected::kNo, UseAllocator::kYes); 426 427 if (!proxy) { 428 return nullptr; 429 } 430 431 SkASSERT(proxy->dimensions() == bitmap.dimensions()); 432 433 return proxy; 434} 435 436sk_sp<GrTextureProxy> GrProxyProvider::createProxy(const GrBackendFormat& format, 437 SkISize dimensions, 438 GrRenderable renderable, 439 int renderTargetSampleCnt, 440 GrMipmapped mipMapped, 441 SkBackingFit fit, 442 SkBudgeted budgeted, 443 GrProtected isProtected, 444 GrInternalSurfaceFlags surfaceFlags, 445 GrSurfaceProxy::UseAllocator useAllocator) { 446 ASSERT_SINGLE_OWNER 447 if (this->isAbandoned()) { 448 return nullptr; 449 } 450 451 const GrCaps* caps = this->caps(); 452 453 if (caps->isFormatCompressed(format)) { 454 // Deferred proxies for compressed textures are not supported. 455 return nullptr; 456 } 457 458 if (GrMipmapped::kYes == mipMapped) { 459 // SkMipmap doesn't include the base level in the level count so we have to add 1 460 int mipCount = SkMipmap::ComputeLevelCount(dimensions.fWidth, dimensions.fHeight) + 1; 461 if (1 == mipCount) { 462 mipMapped = GrMipmapped::kNo; 463 } 464 } 465 466 if (!caps->validateSurfaceParams(dimensions, 467 format, 468 renderable, 469 renderTargetSampleCnt, 470 mipMapped, 471 GrTextureType::k2D)) { 472 return nullptr; 473 } 474 GrMipmapStatus mipmapStatus = (GrMipmapped::kYes == mipMapped) 475 ? GrMipmapStatus::kDirty 476 : GrMipmapStatus::kNotAllocated; 477 if (renderable == GrRenderable::kYes) { 478 renderTargetSampleCnt = caps->getRenderTargetSampleCount(renderTargetSampleCnt, format); 479 SkASSERT(renderTargetSampleCnt); 480 GrInternalSurfaceFlags extraFlags = caps->getExtraSurfaceFlagsForDeferredRT(); 481 // We know anything we instantiate later from this deferred path will be 482 // both texturable and renderable 483 return assignTagToProxy(sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy( 484 *caps, format, dimensions, renderTargetSampleCnt, mipMapped, mipmapStatus, fit, 485 budgeted, isProtected, surfaceFlags | extraFlags, useAllocator, 486 this->isDDLProvider()))); 487 } 488 489 return assignTagToProxy(sk_sp<GrTextureProxy>(new GrTextureProxy(format, dimensions, mipMapped, mipmapStatus, 490 fit, budgeted, isProtected, surfaceFlags, 491 useAllocator, this->isDDLProvider()))); 492} 493 494sk_sp<GrTextureProxy> GrProxyProvider::createCompressedTextureProxy( 495 SkISize dimensions, SkBudgeted budgeted, GrMipmapped mipMapped, GrProtected isProtected, 496 SkImage::CompressionType compressionType, sk_sp<SkData> data) { 497 ASSERT_SINGLE_OWNER 498 if (this->isAbandoned()) { 499 return nullptr; 500 } 501 502 GrBackendFormat format = this->caps()->getBackendFormatFromCompressionType(compressionType); 503 504 if (!this->caps()->isFormatTexturable(format, GrTextureType::k2D)) { 505 return nullptr; 506 } 507 508 GrMipmapStatus mipmapStatus = (GrMipmapped::kYes == mipMapped) ? GrMipmapStatus::kValid 509 : GrMipmapStatus::kNotAllocated; 510 511 sk_sp<GrTextureProxy> proxy = this->createLazyProxy( 512 [data](GrResourceProvider* resourceProvider, const LazySurfaceDesc& desc) { 513 return LazyCallbackResult(resourceProvider->createCompressedTexture( 514 desc.fDimensions, desc.fFormat, desc.fBudgeted, desc.fMipmapped, 515 desc.fProtected, data.get())); 516 }, 517 format, dimensions, mipMapped, mipmapStatus,GrInternalSurfaceFlags::kReadOnly, 518 SkBackingFit::kExact, SkBudgeted::kYes, GrProtected::kNo, UseAllocator::kYes); 519 520 if (!proxy) { 521 return nullptr; 522 } 523 524 auto direct = fImageContext->asDirectContext(); 525 if (direct) { 526 GrResourceProvider* resourceProvider = direct->priv().resourceProvider(); 527 // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however 528 // we're better off instantiating the proxy immediately here. 529 if (!proxy->priv().doLazyInstantiation(resourceProvider)) { 530 return nullptr; 531 } 532 } 533 return proxy; 534} 535 536sk_sp<GrTextureProxy> GrProxyProvider::wrapBackendTexture(const GrBackendTexture& backendTex, 537 GrWrapOwnership ownership, 538 GrWrapCacheable cacheable, 539 GrIOType ioType, 540 sk_sp<GrRefCntedCallback> releaseHelper) { 541 SkASSERT(ioType != kWrite_GrIOType); 542 543 if (this->isAbandoned()) { 544 return nullptr; 545 } 546 547 // This is only supported on a direct GrContext. 548 auto direct = fImageContext->asDirectContext(); 549 if (!direct) { 550 return nullptr; 551 } 552 553 GrResourceProvider* resourceProvider = direct->priv().resourceProvider(); 554 555 sk_sp<GrTexture> tex = 556 resourceProvider->wrapBackendTexture(backendTex, ownership, cacheable, ioType); 557 if (!tex) { 558 return nullptr; 559 } 560 561 if (releaseHelper) { 562 tex->setRelease(std::move(releaseHelper)); 563 } 564 565 SkASSERT(!tex->asRenderTarget()); // Strictly a GrTexture 566 // Make sure we match how we created the proxy with SkBudgeted::kNo 567 SkASSERT(GrBudgetedType::kBudgeted != tex->resourcePriv().budgetedType()); 568 569 return assignTagToProxy(sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(tex), UseAllocator::kNo, 570 this->isDDLProvider()))); 571} 572 573sk_sp<GrTextureProxy> GrProxyProvider::wrapCompressedBackendTexture( 574 const GrBackendTexture& beTex, 575 GrWrapOwnership ownership, 576 GrWrapCacheable cacheable, 577 sk_sp<GrRefCntedCallback> releaseHelper) { 578 if (this->isAbandoned()) { 579 return nullptr; 580 } 581 582 // This is only supported on a direct GrContext. 583 auto direct = fImageContext->asDirectContext(); 584 if (!direct) { 585 return nullptr; 586 } 587 588 GrResourceProvider* resourceProvider = direct->priv().resourceProvider(); 589 590 sk_sp<GrTexture> tex = resourceProvider->wrapCompressedBackendTexture(beTex, ownership, 591 cacheable); 592 if (!tex) { 593 return nullptr; 594 } 595 596 if (releaseHelper) { 597 tex->setRelease(std::move(releaseHelper)); 598 } 599 600 SkASSERT(!tex->asRenderTarget()); // Strictly a GrTexture 601 // Make sure we match how we created the proxy with SkBudgeted::kNo 602 SkASSERT(GrBudgetedType::kBudgeted != tex->resourcePriv().budgetedType()); 603 604 return assignTagToProxy(sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(tex), UseAllocator::kNo, 605 this->isDDLProvider()))); 606} 607 608sk_sp<GrTextureProxy> GrProxyProvider::wrapRenderableBackendTexture( 609 const GrBackendTexture& backendTex, 610 int sampleCnt, 611 GrWrapOwnership ownership, 612 GrWrapCacheable cacheable, 613 sk_sp<GrRefCntedCallback> releaseHelper) { 614 if (this->isAbandoned()) { 615 return nullptr; 616 } 617 618 // This is only supported on a direct GrContext. 619 auto direct = fImageContext->asDirectContext(); 620 if (!direct) { 621 return nullptr; 622 } 623 624 const GrCaps* caps = this->caps(); 625 626 GrResourceProvider* resourceProvider = direct->priv().resourceProvider(); 627 628 sampleCnt = caps->getRenderTargetSampleCount(sampleCnt, backendTex.getBackendFormat()); 629 SkASSERT(sampleCnt); 630 631 sk_sp<GrTexture> tex = resourceProvider->wrapRenderableBackendTexture( 632 backendTex, sampleCnt, ownership, cacheable); 633 if (!tex) { 634 return nullptr; 635 } 636 637 if (releaseHelper) { 638 tex->setRelease(std::move(releaseHelper)); 639 } 640 641 SkASSERT(tex->asRenderTarget()); // A GrTextureRenderTarget 642 // Make sure we match how we created the proxy with SkBudgeted::kNo 643 SkASSERT(GrBudgetedType::kBudgeted != tex->resourcePriv().budgetedType()); 644 645 return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(std::move(tex), UseAllocator::kNo, 646 this->isDDLProvider())); 647 return assignTagToProxy(sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(std::move(tex), UseAllocator::kNo, 648 this->isDDLProvider()))); 649} 650 651sk_sp<GrSurfaceProxy> GrProxyProvider::wrapBackendRenderTarget( 652 const GrBackendRenderTarget& backendRT, 653 sk_sp<GrRefCntedCallback> releaseHelper) { 654 if (this->isAbandoned()) { 655 return nullptr; 656 } 657 658 // This is only supported on a direct GrContext. 659 auto direct = fImageContext->asDirectContext(); 660 if (!direct) { 661 return nullptr; 662 } 663 664 GrResourceProvider* resourceProvider = direct->priv().resourceProvider(); 665 666 sk_sp<GrRenderTarget> rt = resourceProvider->wrapBackendRenderTarget(backendRT); 667 if (!rt) { 668 return nullptr; 669 } 670 671 if (releaseHelper) { 672 rt->setRelease(std::move(releaseHelper)); 673 } 674 675 SkASSERT(!rt->asTexture()); // A GrRenderTarget that's not textureable 676 SkASSERT(!rt->getUniqueKey().isValid()); 677 // Make sure we match how we created the proxy with SkBudgeted::kNo 678 SkASSERT(GrBudgetedType::kBudgeted != rt->resourcePriv().budgetedType()); 679 return assignTagToProxy(sk_sp<GrRenderTargetProxy>(new GrRenderTargetProxy(std::move(rt), UseAllocator::kNo))); 680} 681 682#ifdef SK_VULKAN 683sk_sp<GrRenderTargetProxy> GrProxyProvider::wrapVulkanSecondaryCBAsRenderTarget( 684 const SkImageInfo& imageInfo, const GrVkDrawableInfo& vkInfo) { 685 if (this->isAbandoned()) { 686 return nullptr; 687 } 688 689 // This is only supported on a direct GrContext. 690 auto direct = fImageContext->asDirectContext(); 691 if (!direct) { 692 return nullptr; 693 } 694 695 GrResourceProvider* resourceProvider = direct->priv().resourceProvider(); 696 697 sk_sp<GrRenderTarget> rt = resourceProvider->wrapVulkanSecondaryCBAsRenderTarget(imageInfo, 698 vkInfo); 699 if (!rt) { 700 return nullptr; 701 } 702 703 SkASSERT(!rt->asTexture()); // A GrRenderTarget that's not textureable 704 SkASSERT(!rt->getUniqueKey().isValid()); 705 // This proxy should be unbudgeted because we're just wrapping an external resource 706 SkASSERT(GrBudgetedType::kBudgeted != rt->resourcePriv().budgetedType()); 707 708 GrColorType colorType = SkColorTypeToGrColorType(imageInfo.colorType()); 709 710 if (!this->caps()->isFormatAsColorTypeRenderable( 711 colorType, GrBackendFormat::MakeVk(vkInfo.fFormat), /*sampleCount=*/1)) { 712 return nullptr; 713 } 714 715 return assignTagToProxy(sk_sp<GrRenderTargetProxy>(new GrRenderTargetProxy( 716 std::move(rt), UseAllocator::kNo, GrRenderTargetProxy::WrapsVkSecondaryCB::kYes))); 717} 718#else 719sk_sp<GrRenderTargetProxy> GrProxyProvider::wrapVulkanSecondaryCBAsRenderTarget( 720 const SkImageInfo&, const GrVkDrawableInfo&) { 721 return nullptr; 722} 723#endif 724 725sk_sp<GrTextureProxy> GrProxyProvider::CreatePromiseProxy(GrContextThreadSafeProxy* threadSafeProxy, 726 LazyInstantiateCallback&& callback, 727 const GrBackendFormat& format, 728 SkISize dimensions, 729 GrMipmapped mipMapped) { 730 if (threadSafeProxy->priv().abandoned()) { 731 return nullptr; 732 } 733 SkASSERT((dimensions.fWidth <= 0 && dimensions.fHeight <= 0) || 734 (dimensions.fWidth > 0 && dimensions.fHeight > 0)); 735 736 if (dimensions.fWidth > threadSafeProxy->priv().caps()->maxTextureSize() || 737 dimensions.fHeight > threadSafeProxy->priv().caps()->maxTextureSize()) { 738 return nullptr; 739 } 740 // Ganesh assumes that, when wrapping a mipmapped backend texture from a client, that its 741 // mipmaps are fully fleshed out. 742 GrMipmapStatus mipmapStatus = (GrMipmapped::kYes == mipMapped) ? GrMipmapStatus::kValid 743 : GrMipmapStatus::kNotAllocated; 744 745 // We pass kReadOnly here since we should treat content of the client's texture as immutable. 746 // The promise API provides no way for the client to indicate that the texture is protected. 747 auto proxy = sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(callback), 748 format, 749 dimensions, 750 mipMapped, 751 mipmapStatus, 752 SkBackingFit::kExact, 753 SkBudgeted::kNo, 754 GrProtected::kNo, 755 GrInternalSurfaceFlags::kReadOnly, 756 GrSurfaceProxy::UseAllocator::kYes, 757 GrDDLProvider::kYes)); 758 proxy->priv().setIsPromiseProxy(); 759 return proxy; 760} 761 762sk_sp<GrTextureProxy> GrProxyProvider::createLazyProxy(LazyInstantiateCallback&& callback, 763 const GrBackendFormat& format, 764 SkISize dimensions, 765 GrMipmapped mipMapped, 766 GrMipmapStatus mipmapStatus, 767 GrInternalSurfaceFlags surfaceFlags, 768 SkBackingFit fit, 769 SkBudgeted budgeted, 770 GrProtected isProtected, 771 GrSurfaceProxy::UseAllocator useAllocator) { 772 ASSERT_SINGLE_OWNER 773 if (this->isAbandoned()) { 774 return nullptr; 775 } 776 SkASSERT((dimensions.fWidth <= 0 && dimensions.fHeight <= 0) || 777 (dimensions.fWidth > 0 && dimensions.fHeight > 0)); 778 779 if (!format.isValid() || format.backend() != fImageContext->backend()) { 780 return nullptr; 781 } 782 783 if (dimensions.fWidth > this->caps()->maxTextureSize() || 784 dimensions.fHeight > this->caps()->maxTextureSize()) { 785 return nullptr; 786 } 787 788 return assignTagToProxy(sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(callback), 789 format, 790 dimensions, 791 mipMapped, 792 mipmapStatus, 793 fit, 794 budgeted, 795 isProtected, 796 surfaceFlags, 797 useAllocator, 798 this->isDDLProvider()))); 799} 800 801sk_sp<GrRenderTargetProxy> GrProxyProvider::createLazyRenderTargetProxy( 802 LazyInstantiateCallback&& callback, 803 const GrBackendFormat& format, 804 SkISize dimensions, 805 int sampleCnt, 806 GrInternalSurfaceFlags surfaceFlags, 807 const TextureInfo* textureInfo, 808 GrMipmapStatus mipmapStatus, 809 SkBackingFit fit, 810 SkBudgeted budgeted, 811 GrProtected isProtected, 812 bool wrapsVkSecondaryCB, 813 UseAllocator useAllocator) { 814 ASSERT_SINGLE_OWNER 815 if (this->isAbandoned()) { 816 return nullptr; 817 } 818 SkASSERT((dimensions.fWidth <= 0 && dimensions.fHeight <= 0) || 819 (dimensions.fWidth > 0 && dimensions.fHeight > 0)); 820 821 if (dimensions.fWidth > this->caps()->maxRenderTargetSize() || 822 dimensions.fHeight > this->caps()->maxRenderTargetSize()) { 823 return nullptr; 824 } 825 826 if (textureInfo) { 827 // Wrapped vulkan secondary command buffers don't support texturing since we won't have an 828 // actual VkImage to texture from. 829 SkASSERT(!wrapsVkSecondaryCB); 830 return assignTagToProxy(sk_sp<GrRenderTargetProxy>(new GrTextureRenderTargetProxy( 831 *this->caps(), std::move(callback), format, dimensions, sampleCnt, 832 textureInfo->fMipmapped, mipmapStatus, fit, budgeted, isProtected, surfaceFlags, 833 useAllocator, this->isDDLProvider()))); 834 } 835 836 GrRenderTargetProxy::WrapsVkSecondaryCB vkSCB = 837 wrapsVkSecondaryCB ? GrRenderTargetProxy::WrapsVkSecondaryCB::kYes 838 : GrRenderTargetProxy::WrapsVkSecondaryCB::kNo; 839 840 return assignTagToProxy(sk_sp<GrRenderTargetProxy>( 841 new GrRenderTargetProxy(std::move(callback), format, dimensions, sampleCnt, fit, 842 budgeted, isProtected, surfaceFlags, useAllocator, vkSCB))); 843} 844 845sk_sp<GrTextureProxy> GrProxyProvider::MakeFullyLazyProxy(LazyInstantiateCallback&& callback, 846 const GrBackendFormat& format, 847 GrRenderable renderable, 848 int renderTargetSampleCnt, 849 GrProtected isProtected, 850 const GrCaps& caps, 851 UseAllocator useAllocator) { 852 if (!format.isValid()) { 853 return nullptr; 854 } 855 856 SkASSERT(renderTargetSampleCnt == 1 || renderable == GrRenderable::kYes); 857 // TODO: If we ever have callers requesting specific surface flags then we shouldn't use the 858 // extra deferred flags here. Instead those callers should all pass in exactly what they want. 859 // However, as of today all uses of this essentially create a deferred proxy in the end. 860 GrInternalSurfaceFlags surfaceFlags = caps.getExtraSurfaceFlagsForDeferredRT(); 861 862 // MakeFullyLazyProxy is only called at flush time so we know these texture proxies are 863 // not being created by a DDL provider. 864 static constexpr SkISize kLazyDims = {-1, -1}; 865 if (GrRenderable::kYes == renderable) { 866 return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy( 867 caps, std::move(callback), format, kLazyDims, renderTargetSampleCnt, 868 GrMipmapped::kNo, GrMipmapStatus::kNotAllocated, SkBackingFit::kApprox, 869 SkBudgeted::kYes, isProtected, surfaceFlags, useAllocator, GrDDLProvider::kNo)); 870 } else { 871 return sk_sp<GrTextureProxy>( 872 new GrTextureProxy(std::move(callback), format, kLazyDims, GrMipmapped::kNo, 873 GrMipmapStatus::kNotAllocated, SkBackingFit::kApprox, 874 SkBudgeted::kYes, isProtected, surfaceFlags, useAllocator, 875 GrDDLProvider::kNo)); 876 } 877} 878 879void GrProxyProvider::processInvalidUniqueKey(const GrUniqueKey& key, GrTextureProxy* proxy, 880 InvalidateGPUResource invalidateGPUResource) { 881 this->processInvalidUniqueKeyImpl(key, proxy, invalidateGPUResource, RemoveTableEntry::kYes); 882} 883 884void GrProxyProvider::processInvalidUniqueKeyImpl(const GrUniqueKey& key, GrTextureProxy* proxy, 885 InvalidateGPUResource invalidateGPUResource, 886 RemoveTableEntry removeTableEntry) { 887 SkASSERT(key.isValid()); 888 889 if (!proxy) { 890 proxy = fUniquelyKeyedProxies.find(key); 891 } 892 SkASSERT(!proxy || proxy->getUniqueKey() == key); 893 894 // Locate the corresponding GrGpuResource (if it needs to be invalidated) before clearing the 895 // proxy's unique key. We must do it in this order because 'key' may alias the proxy's key. 896 sk_sp<GrGpuResource> invalidGpuResource; 897 if (InvalidateGPUResource::kYes == invalidateGPUResource) { 898 auto direct = fImageContext->asDirectContext(); 899 if (direct) { 900 GrResourceProvider* resourceProvider = direct->priv().resourceProvider(); 901 invalidGpuResource = resourceProvider->findByUniqueKey<GrGpuResource>(key); 902 } 903 SkASSERT(!invalidGpuResource || invalidGpuResource->getUniqueKey() == key); 904 } 905 906 // Note: this method is called for the whole variety of GrGpuResources so often 'key' 907 // will not be in 'fUniquelyKeyedProxies'. 908 if (proxy) { 909 if (removeTableEntry == RemoveTableEntry::kYes) { 910 fUniquelyKeyedProxies.remove(key); 911 } 912 proxy->cacheAccess().clearUniqueKey(); 913 } 914 915 if (invalidGpuResource) { 916 invalidGpuResource->resourcePriv().removeUniqueKey(); 917 } 918} 919 920GrDDLProvider GrProxyProvider::isDDLProvider() const { 921 return fImageContext->asDirectContext() ? GrDDLProvider::kNo : GrDDLProvider::kYes; 922} 923 924uint32_t GrProxyProvider::contextID() const { 925 return fImageContext->priv().contextID(); 926} 927 928const GrCaps* GrProxyProvider::caps() const { 929 return fImageContext->priv().caps(); 930} 931 932sk_sp<const GrCaps> GrProxyProvider::refCaps() const { 933 return fImageContext->priv().refCaps(); 934} 935 936bool GrProxyProvider::isAbandoned() const { 937 return fImageContext->priv().abandoned(); 938} 939 940void GrProxyProvider::orphanAllUniqueKeys() { 941 fUniquelyKeyedProxies.foreach([&](GrTextureProxy* proxy){ 942 proxy->fProxyProvider = nullptr; 943 }); 944} 945 946void GrProxyProvider::removeAllUniqueKeys() { 947 fUniquelyKeyedProxies.foreach([&](GrTextureProxy* proxy){ 948 // It's not safe to remove table entries while iterating with foreach(), 949 // but since we're going to remove them all anyway, simply save that for the end. 950 this->processInvalidUniqueKeyImpl(proxy->getUniqueKey(), proxy, 951 InvalidateGPUResource::kNo, 952 RemoveTableEntry::kNo); 953 }); 954 // Removing all those table entries is safe now. 955 fUniquelyKeyedProxies.reset(); 956} 957 958bool GrProxyProvider::renderingDirectly() const { 959 return fImageContext->asDirectContext(); 960} 961