| /* | 
 |  * Copyright 2018 Google Inc. | 
 |  * | 
 |  * Use of this source code is governed by a BSD-style license that can be | 
 |  * found in the LICENSE file. | 
 |  */ | 
 |  | 
 | #include "GrProxyProvider.h" | 
 |  | 
 | #include "GrCaps.h" | 
 | #include "GrRenderTarget.h" | 
 | #include "GrResourceKey.h" | 
 | #include "GrResourceProvider.h" | 
 | #include "GrSurfaceProxy.h" | 
 | #include "GrSurfaceProxyPriv.h" | 
 | #include "GrTexture.h" | 
 | #include "GrTextureProxyCacheAccess.h" | 
 | #include "GrTextureRenderTargetProxy.h" | 
 | #include "../private/GrSingleOwner.h" | 
 | #include "SkAutoPixmapStorage.h" | 
 | #include "SkBitmap.h" | 
 | #include "SkGr.h" | 
 | #include "SkImage.h" | 
 | #include "SkImage_Base.h" | 
 | #include "SkImageInfoPriv.h" | 
 | #include "SkImagePriv.h" | 
 | #include "SkMipMap.h" | 
 | #include "SkTraceEvent.h" | 
 |  | 
 | #define ASSERT_SINGLE_OWNER \ | 
 |     SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);) | 
 |  | 
 | GrProxyProvider::GrProxyProvider(GrResourceProvider* resourceProvider, | 
 |                                  GrResourceCache* resourceCache, | 
 |                                  sk_sp<const GrCaps> caps, | 
 |                                  GrSingleOwner* owner) | 
 |         : fResourceProvider(resourceProvider) | 
 |         , fResourceCache(resourceCache) | 
 |         , fAbandoned(false) | 
 |         , fCaps(caps) | 
 |         , fContextUniqueID(resourceCache->contextUniqueID()) | 
 | #ifdef SK_DEBUG | 
 |         , fSingleOwner(owner) | 
 | #endif | 
 | { | 
 |     SkASSERT(fResourceProvider); | 
 |     SkASSERT(fResourceCache); | 
 |     SkASSERT(fCaps); | 
 |     SkASSERT(fSingleOwner); | 
 | } | 
 |  | 
 | GrProxyProvider::GrProxyProvider(uint32_t contextUniqueID, | 
 |                                  sk_sp<const GrCaps> caps, | 
 |                                  GrSingleOwner* owner) | 
 |         : fResourceProvider(nullptr) | 
 |         , fResourceCache(nullptr) | 
 |         , fAbandoned(false) | 
 |         , fCaps(caps) | 
 |         , fContextUniqueID(contextUniqueID) | 
 | #ifdef SK_DEBUG | 
 |         , fSingleOwner(owner) | 
 | #endif | 
 | { | 
 |     SkASSERT(fContextUniqueID != SK_InvalidUniqueID); | 
 |     SkASSERT(fCaps); | 
 |     SkASSERT(fSingleOwner); | 
 | } | 
 |  | 
 | GrProxyProvider::~GrProxyProvider() { | 
 |     if (fResourceCache) { | 
 |         // In DDL-mode a proxy provider can still have extant uniquely keyed proxies (since | 
 |         // they need their unique keys to, potentially, find a cached resource when the | 
 |         // DDL is played) but, in non-DDL-mode they should all have been cleaned up by this point. | 
 |         SkASSERT(!fUniquelyKeyedProxies.count()); | 
 |     } | 
 | } | 
 |  | 
 | bool GrProxyProvider::assignUniqueKeyToProxy(const GrUniqueKey& key, GrTextureProxy* proxy) { | 
 |     ASSERT_SINGLE_OWNER | 
 |     SkASSERT(key.isValid()); | 
 |     if (this->isAbandoned() || !proxy) { | 
 |         return false; | 
 |     } | 
 |  | 
 |     // If there is already a GrResource with this key then the caller has violated the normal | 
 |     // usage pattern of uniquely keyed resources (e.g., they have created one w/o first seeing | 
 |     // if it already existed in the cache). | 
 |     SkASSERT(!fResourceCache || !fResourceCache->findAndRefUniqueResource(key)); | 
 |  | 
 |     SkASSERT(!fUniquelyKeyedProxies.find(key));     // multiple proxies can't get the same key | 
 |  | 
 |     proxy->cacheAccess().setUniqueKey(this, key); | 
 |     SkASSERT(proxy->getUniqueKey() == key); | 
 |     fUniquelyKeyedProxies.add(proxy); | 
 |     return true; | 
 | } | 
 |  | 
 | void GrProxyProvider::adoptUniqueKeyFromSurface(GrTextureProxy* proxy, const GrSurface* surf) { | 
 |     SkASSERT(surf->getUniqueKey().isValid()); | 
 |     proxy->cacheAccess().setUniqueKey(this, surf->getUniqueKey()); | 
 |     SkASSERT(proxy->getUniqueKey() == surf->getUniqueKey()); | 
 |     // multiple proxies can't get the same key | 
 |     SkASSERT(!fUniquelyKeyedProxies.find(surf->getUniqueKey())); | 
 |     fUniquelyKeyedProxies.add(proxy); | 
 | } | 
 |  | 
 | void GrProxyProvider::removeUniqueKeyFromProxy(GrTextureProxy* proxy) { | 
 |     ASSERT_SINGLE_OWNER | 
 |     SkASSERT(proxy); | 
 |     SkASSERT(proxy->getUniqueKey().isValid()); | 
 |  | 
 |     if (this->isAbandoned()) { | 
 |         return; | 
 |     } | 
 |  | 
 |     this->processInvalidUniqueKey(proxy->getUniqueKey(), proxy, InvalidateGPUResource::kYes); | 
 | } | 
 |  | 
 | sk_sp<GrTextureProxy> GrProxyProvider::findProxyByUniqueKey(const GrUniqueKey& key, | 
 |                                                             GrSurfaceOrigin origin) { | 
 |     ASSERT_SINGLE_OWNER | 
 |  | 
 |     if (this->isAbandoned()) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     sk_sp<GrTextureProxy> result = sk_ref_sp(fUniquelyKeyedProxies.find(key)); | 
 |     if (result) { | 
 |         SkASSERT(result->origin() == origin); | 
 |     } | 
 |     return result; | 
 | } | 
 |  | 
 | sk_sp<GrTextureProxy> GrProxyProvider::createWrapped(sk_sp<GrTexture> tex, GrSurfaceOrigin origin) { | 
 | #ifdef SK_DEBUG | 
 |     if (tex->getUniqueKey().isValid()) { | 
 |         SkASSERT(!this->findProxyByUniqueKey(tex->getUniqueKey(), origin)); | 
 |     } | 
 | #endif | 
 |  | 
 |     if (tex->asRenderTarget()) { | 
 |         return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(std::move(tex), origin)); | 
 |     } else { | 
 |         return sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(tex), origin)); | 
 |     } | 
 | } | 
 |  | 
 | sk_sp<GrTextureProxy> GrProxyProvider::findOrCreateProxyByUniqueKey(const GrUniqueKey& key, | 
 |                                                                     GrSurfaceOrigin origin) { | 
 |     ASSERT_SINGLE_OWNER | 
 |  | 
 |     if (this->isAbandoned()) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     sk_sp<GrTextureProxy> result = this->findProxyByUniqueKey(key, origin); | 
 |     if (result) { | 
 |         return result; | 
 |     } | 
 |  | 
 |     if (!fResourceCache) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     GrGpuResource* resource = fResourceCache->findAndRefUniqueResource(key); | 
 |     if (!resource) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     sk_sp<GrTexture> texture(static_cast<GrSurface*>(resource)->asTexture()); | 
 |     SkASSERT(texture); | 
 |  | 
 |     result = this->createWrapped(std::move(texture), origin); | 
 |     SkASSERT(result->getUniqueKey() == key); | 
 |     // createWrapped should've added this for us | 
 |     SkASSERT(fUniquelyKeyedProxies.find(key)); | 
 |     return result; | 
 | } | 
 |  | 
 | sk_sp<GrTextureProxy> GrProxyProvider::createTextureProxy(sk_sp<SkImage> srcImage, | 
 |                                                           GrSurfaceDescFlags descFlags, | 
 |                                                           int sampleCnt, | 
 |                                                           SkBudgeted budgeted, | 
 |                                                           SkBackingFit fit, | 
 |                                                           GrInternalSurfaceFlags surfaceFlags) { | 
 |     ASSERT_SINGLE_OWNER | 
 |     SkASSERT(srcImage); | 
 |  | 
 |     if (this->isAbandoned()) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     SkImageInfo info = as_IB(srcImage)->onImageInfo(); | 
 |     GrPixelConfig config = SkImageInfo2GrPixelConfig(info); | 
 |  | 
 |     if (kUnknown_GrPixelConfig == config) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     GrBackendFormat format = fCaps->getBackendFormatFromColorType(info.colorType()); | 
 |     if (!format.isValid()) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     if (!this->caps()->isConfigTexturable(config)) { | 
 |         SkBitmap copy8888; | 
 |         if (!copy8888.tryAllocPixels(info.makeColorType(kRGBA_8888_SkColorType)) || | 
 |             !srcImage->readPixels(copy8888.pixmap(), 0, 0)) { | 
 |             return nullptr; | 
 |         } | 
 |         copy8888.setImmutable(); | 
 |         srcImage = SkMakeImageFromRasterBitmap(copy8888, kNever_SkCopyPixelsMode); | 
 |         config = kRGBA_8888_GrPixelConfig; | 
 |     } | 
 |  | 
 |     if (SkToBool(descFlags & kRenderTarget_GrSurfaceFlag)) { | 
 |         sampleCnt = this->caps()->getRenderTargetSampleCount(sampleCnt, config); | 
 |         if (!sampleCnt) { | 
 |             return nullptr; | 
 |         } | 
 |     } | 
 |  | 
 |     if (SkToBool(descFlags & kRenderTarget_GrSurfaceFlag)) { | 
 |         if (fCaps->usesMixedSamples() && sampleCnt > 1) { | 
 |             surfaceFlags |= GrInternalSurfaceFlags::kMixedSampled; | 
 |         } | 
 |     } | 
 |  | 
 |     GrSurfaceDesc desc; | 
 |     desc.fWidth = srcImage->width(); | 
 |     desc.fHeight = srcImage->height(); | 
 |     desc.fFlags = descFlags; | 
 |     desc.fSampleCnt = sampleCnt; | 
 |     desc.fConfig = config; | 
 |  | 
 |     sk_sp<GrTextureProxy> proxy = this->createLazyProxy( | 
 |             [desc, budgeted, srcImage, fit, surfaceFlags](GrResourceProvider* resourceProvider) { | 
 |                 if (!resourceProvider) { | 
 |                     // Nothing to clean up here. Once the proxy (and thus lambda) is deleted the ref | 
 |                     // on srcImage will be released. | 
 |                     return sk_sp<GrTexture>(); | 
 |                 } | 
 |                 SkPixmap pixMap; | 
 |                 SkAssertResult(srcImage->peekPixels(&pixMap)); | 
 |                 GrMipLevel mipLevel = { pixMap.addr(), pixMap.rowBytes() }; | 
 |  | 
 |                 auto resourceProviderFlags = GrResourceProvider::Flags::kNone; | 
 |                 if (surfaceFlags & GrInternalSurfaceFlags::kNoPendingIO) { | 
 |                     resourceProviderFlags |= GrResourceProvider::Flags::kNoPendingIO; | 
 |                 } | 
 |                 return resourceProvider->createTexture(desc, budgeted, fit, mipLevel, | 
 |                                                        resourceProviderFlags); | 
 |             }, | 
 |             format, desc, kTopLeft_GrSurfaceOrigin, GrMipMapped::kNo, surfaceFlags, fit, budgeted); | 
 |  | 
 |     if (!proxy) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     if (fResourceProvider) { | 
 |         // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however | 
 |         // we're better off instantiating the proxy immediately here. | 
 |         if (!proxy->priv().doLazyInstantiation(fResourceProvider)) { | 
 |             return nullptr; | 
 |         } | 
 |     } | 
 |  | 
 |     SkASSERT(proxy->width() == desc.fWidth); | 
 |     SkASSERT(proxy->height() == desc.fHeight); | 
 |     return proxy; | 
 | } | 
 |  | 
 | sk_sp<GrTextureProxy> GrProxyProvider::createMipMapProxy(const GrBackendFormat& format, | 
 |                                                          const GrSurfaceDesc& desc, | 
 |                                                          GrSurfaceOrigin origin, | 
 |                                                          SkBudgeted budgeted) { | 
 |     ASSERT_SINGLE_OWNER | 
 |  | 
 |     if (this->isAbandoned()) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     return this->createProxy(format, desc, origin, GrMipMapped::kYes, SkBackingFit::kExact, | 
 |                              budgeted, GrInternalSurfaceFlags::kNone); | 
 | } | 
 |  | 
 | sk_sp<GrTextureProxy> GrProxyProvider::createMipMapProxyFromBitmap(const SkBitmap& bitmap) { | 
 |     if (!SkImageInfoIsValid(bitmap.info())) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     ATRACE_ANDROID_FRAMEWORK("Upload MipMap Texture [%ux%u]", bitmap.width(), bitmap.height()); | 
 |  | 
 |     // In non-ddl we will always instantiate right away. Thus we never want to copy the SkBitmap | 
 |     // even if its mutable. In ddl, if the bitmap is mutable then we must make a copy since the | 
 |     // upload of the data to the gpu can happen at anytime and the bitmap may change by then. | 
 |     SkCopyPixelsMode copyMode = this->recordingDDL() ? kIfMutable_SkCopyPixelsMode | 
 |                                                      : kNever_SkCopyPixelsMode; | 
 |     sk_sp<SkImage> baseLevel = SkMakeImageFromRasterBitmap(bitmap, copyMode); | 
 |     if (!baseLevel) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     // This was never going to have mips anyway | 
 |     if (0 == SkMipMap::ComputeLevelCount(baseLevel->width(), baseLevel->height())) { | 
 |         return this->createTextureProxy(baseLevel, kNone_GrSurfaceFlags, 1, SkBudgeted::kYes, | 
 |                                         SkBackingFit::kExact); | 
 |     } | 
 |  | 
 |     const GrBackendFormat format = fCaps->getBackendFormatFromColorType(bitmap.info().colorType()); | 
 |     if (!format.isValid()) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bitmap.info()); | 
 |     if (!this->caps()->isConfigTexturable(desc.fConfig)) { | 
 |         SkBitmap copy8888; | 
 |         if (!copy8888.tryAllocPixels(bitmap.info().makeColorType(kRGBA_8888_SkColorType)) || | 
 |             !bitmap.readPixels(copy8888.pixmap())) { | 
 |             return nullptr; | 
 |         } | 
 |         copy8888.setImmutable(); | 
 |         baseLevel = SkMakeImageFromRasterBitmap(copy8888, kNever_SkCopyPixelsMode); | 
 |         desc.fConfig = kRGBA_8888_GrPixelConfig; | 
 |     } | 
 |  | 
 |     SkPixmap pixmap; | 
 |     SkAssertResult(baseLevel->peekPixels(&pixmap)); | 
 |     sk_sp<SkMipMap> mipmaps(SkMipMap::Build(pixmap, nullptr)); | 
 |     if (!mipmaps) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     sk_sp<GrTextureProxy> proxy = this->createLazyProxy( | 
 |             [desc, baseLevel, mipmaps](GrResourceProvider* resourceProvider) { | 
 |                 if (!resourceProvider) { | 
 |                     return sk_sp<GrTexture>(); | 
 |                 } | 
 |  | 
 |                 const int mipLevelCount = mipmaps->countLevels() + 1; | 
 |                 std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]); | 
 |  | 
 |                 SkPixmap pixmap; | 
 |                 SkAssertResult(baseLevel->peekPixels(&pixmap)); | 
 |  | 
 |                 // DDL TODO: Instead of copying all this info into GrMipLevels we should just plumb | 
 |                 // the use of SkMipMap down through Ganesh. | 
 |                 texels[0].fPixels = pixmap.addr(); | 
 |                 texels[0].fRowBytes = pixmap.rowBytes(); | 
 |  | 
 |                 for (int i = 1; i < mipLevelCount; ++i) { | 
 |                     SkMipMap::Level generatedMipLevel; | 
 |                     mipmaps->getLevel(i - 1, &generatedMipLevel); | 
 |                     texels[i].fPixels = generatedMipLevel.fPixmap.addr(); | 
 |                     texels[i].fRowBytes = generatedMipLevel.fPixmap.rowBytes(); | 
 |                     SkASSERT(texels[i].fPixels); | 
 |                 } | 
 |  | 
 |                 return resourceProvider->createTexture(desc, SkBudgeted::kYes, texels.get(), | 
 |                                                        mipLevelCount); | 
 |             }, | 
 |             format, desc, kTopLeft_GrSurfaceOrigin, GrMipMapped::kYes, SkBackingFit::kExact, | 
 |             SkBudgeted::kYes); | 
 |  | 
 |     if (!proxy) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     if (fResourceProvider) { | 
 |         // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however | 
 |         // we're better off instantiating the proxy immediately here. | 
 |         if (!proxy->priv().doLazyInstantiation(fResourceProvider)) { | 
 |             return nullptr; | 
 |         } | 
 |     } | 
 |     return proxy; | 
 | } | 
 |  | 
 | sk_sp<GrTextureProxy> GrProxyProvider::createProxy(const GrBackendFormat& format, | 
 |                                                    const GrSurfaceDesc& desc, | 
 |                                                    GrSurfaceOrigin origin, | 
 |                                                    GrMipMapped mipMapped, | 
 |                                                    SkBackingFit fit, | 
 |                                                    SkBudgeted budgeted, | 
 |                                                    GrInternalSurfaceFlags surfaceFlags) { | 
 |     if (GrMipMapped::kYes == mipMapped) { | 
 |         // SkMipMap doesn't include the base level in the level count so we have to add 1 | 
 |         int mipCount = SkMipMap::ComputeLevelCount(desc.fWidth, desc.fHeight) + 1; | 
 |         if (1 == mipCount) { | 
 |             mipMapped = GrMipMapped::kNo; | 
 |         } | 
 |     } | 
 |  | 
 |     if (!this->caps()->validateSurfaceDesc(desc, mipMapped)) { | 
 |         return nullptr; | 
 |     } | 
 |     GrSurfaceDesc copyDesc = desc; | 
 |     if (desc.fFlags & kRenderTarget_GrSurfaceFlag) { | 
 |         copyDesc.fSampleCnt = | 
 |                 this->caps()->getRenderTargetSampleCount(desc.fSampleCnt, desc.fConfig); | 
 |     } | 
 |  | 
 |     if (copyDesc.fFlags & kRenderTarget_GrSurfaceFlag) { | 
 |         // We know anything we instantiate later from this deferred path will be | 
 |         // both texturable and renderable | 
 |         return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(*this->caps(), format, copyDesc, | 
 |                                                                     origin, mipMapped, | 
 |                                                                     fit, budgeted, surfaceFlags)); | 
 |     } | 
 |  | 
 |     return sk_sp<GrTextureProxy>(new GrTextureProxy(format, copyDesc, origin, mipMapped, | 
 |                                                     fit, budgeted, surfaceFlags)); | 
 | } | 
 |  | 
 | sk_sp<GrTextureProxy> GrProxyProvider::wrapBackendTexture(const GrBackendTexture& backendTex, | 
 |                                                           GrSurfaceOrigin origin, | 
 |                                                           GrWrapOwnership ownership, | 
 |                                                           GrIOType ioType, | 
 |                                                           ReleaseProc releaseProc, | 
 |                                                           ReleaseContext releaseCtx) { | 
 |     SkASSERT(ioType != kWrite_GrIOType); | 
 |     if (this->isAbandoned()) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     // This is only supported on a direct GrContext. | 
 |     if (!fResourceProvider) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     sk_sp<GrTexture> tex = fResourceProvider->wrapBackendTexture(backendTex, ownership, ioType); | 
 |     if (!tex) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     sk_sp<GrReleaseProcHelper> releaseHelper; | 
 |     if (releaseProc) { | 
 |         releaseHelper.reset(new GrReleaseProcHelper(releaseProc, releaseCtx)); | 
 |         // This gives the texture a ref on the releaseHelper | 
 |         tex->setRelease(releaseHelper); | 
 |     } | 
 |  | 
 |     SkASSERT(!tex->asRenderTarget());  // Strictly a GrTexture | 
 |     // Make sure we match how we created the proxy with SkBudgeted::kNo | 
 |     SkASSERT(SkBudgeted::kNo == tex->resourcePriv().isBudgeted()); | 
 |  | 
 |     return sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(tex), origin)); | 
 | } | 
 |  | 
 | sk_sp<GrTextureProxy> GrProxyProvider::wrapRenderableBackendTexture( | 
 |         const GrBackendTexture& backendTex, GrSurfaceOrigin origin, int sampleCnt, | 
 |         GrWrapOwnership ownership) { | 
 |     if (this->isAbandoned()) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     // This is only supported on a direct GrContext. | 
 |     if (!fResourceProvider) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     sampleCnt = this->caps()->getRenderTargetSampleCount(sampleCnt, backendTex.config()); | 
 |     if (!sampleCnt) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     sk_sp<GrTexture> tex = | 
 |             fResourceProvider->wrapRenderableBackendTexture(backendTex, sampleCnt, ownership); | 
 |     if (!tex) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     SkASSERT(tex->asRenderTarget());  // A GrTextureRenderTarget | 
 |     // Make sure we match how we created the proxy with SkBudgeted::kNo | 
 |     SkASSERT(SkBudgeted::kNo == tex->resourcePriv().isBudgeted()); | 
 |  | 
 |     return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(std::move(tex), origin)); | 
 | } | 
 |  | 
 | sk_sp<GrSurfaceProxy> GrProxyProvider::wrapBackendRenderTarget( | 
 |         const GrBackendRenderTarget& backendRT, GrSurfaceOrigin origin) { | 
 |     if (this->isAbandoned()) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     // This is only supported on a direct GrContext. | 
 |     if (!fResourceProvider) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     sk_sp<GrRenderTarget> rt = fResourceProvider->wrapBackendRenderTarget(backendRT); | 
 |     if (!rt) { | 
 |         return nullptr; | 
 |     } | 
 |     SkASSERT(!rt->asTexture());  // A GrRenderTarget that's not textureable | 
 |     SkASSERT(!rt->getUniqueKey().isValid()); | 
 |     // Make sure we match how we created the proxy with SkBudgeted::kNo | 
 |     SkASSERT(SkBudgeted::kNo == rt->resourcePriv().isBudgeted()); | 
 |  | 
 |     return sk_sp<GrRenderTargetProxy>(new GrRenderTargetProxy(std::move(rt), origin)); | 
 | } | 
 |  | 
 | sk_sp<GrSurfaceProxy> GrProxyProvider::wrapBackendTextureAsRenderTarget( | 
 |         const GrBackendTexture& backendTex, GrSurfaceOrigin origin, int sampleCnt) { | 
 |     if (this->isAbandoned()) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     // This is only supported on a direct GrContext. | 
 |     if (!fResourceProvider) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     sk_sp<GrRenderTarget> rt = | 
 |             fResourceProvider->wrapBackendTextureAsRenderTarget(backendTex, sampleCnt); | 
 |     if (!rt) { | 
 |         return nullptr; | 
 |     } | 
 |     SkASSERT(!rt->asTexture());  // A GrRenderTarget that's not textureable | 
 |     SkASSERT(!rt->getUniqueKey().isValid()); | 
 |     // This proxy should be unbudgeted because we're just wrapping an external resource | 
 |     SkASSERT(SkBudgeted::kNo == rt->resourcePriv().isBudgeted()); | 
 |  | 
 |     return sk_sp<GrSurfaceProxy>(new GrRenderTargetProxy(std::move(rt), origin)); | 
 | } | 
 |  | 
 | sk_sp<GrRenderTargetProxy> GrProxyProvider::wrapVulkanSecondaryCBAsRenderTarget( | 
 |         const SkImageInfo& imageInfo, const GrVkDrawableInfo& vkInfo) { | 
 |     if (this->isAbandoned()) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     // This is only supported on a direct GrContext. | 
 |     if (!fResourceProvider) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     sk_sp<GrRenderTarget> rt = fResourceProvider->wrapVulkanSecondaryCBAsRenderTarget(imageInfo, | 
 |                                                                                       vkInfo); | 
 |  | 
 |     if (!rt) { | 
 |         return nullptr; | 
 |     } | 
 |     SkASSERT(!rt->asTexture());  // A GrRenderTarget that's not textureable | 
 |     SkASSERT(!rt->getUniqueKey().isValid()); | 
 |     // This proxy should be unbudgeted because we're just wrapping an external resource | 
 |     SkASSERT(SkBudgeted::kNo == rt->resourcePriv().isBudgeted()); | 
 |  | 
 |     // All Vulkan surfaces uses top left origins. | 
 |     return sk_sp<GrRenderTargetProxy>( | 
 |             new GrRenderTargetProxy(std::move(rt), | 
 |                                     kTopLeft_GrSurfaceOrigin, | 
 |                                     GrRenderTargetProxy::WrapsVkSecondaryCB::kYes)); | 
 | } | 
 |  | 
 | sk_sp<GrTextureProxy> GrProxyProvider::createLazyProxy(LazyInstantiateCallback&& callback, | 
 |                                                        const GrBackendFormat& format, | 
 |                                                        const GrSurfaceDesc& desc, | 
 |                                                        GrSurfaceOrigin origin, | 
 |                                                        GrMipMapped mipMapped, | 
 |                                                        SkBackingFit fit, | 
 |                                                        SkBudgeted budgeted) { | 
 |     return this->createLazyProxy(std::move(callback), format, desc, origin, mipMapped, | 
 |                                  GrInternalSurfaceFlags::kNone, fit, budgeted); | 
 | } | 
 |  | 
 | sk_sp<GrTextureProxy> GrProxyProvider::createLazyProxy(LazyInstantiateCallback&& callback, | 
 |                                                        const GrBackendFormat& format, | 
 |                                                        const GrSurfaceDesc& desc, | 
 |                                                        GrSurfaceOrigin origin, | 
 |                                                        GrMipMapped mipMapped, | 
 |                                                        GrInternalSurfaceFlags surfaceFlags, | 
 |                                                        SkBackingFit fit, | 
 |                                                        SkBudgeted budgeted) { | 
 |     // For non-ddl draws always make lazy proxy's single use. | 
 |     LazyInstantiationType lazyType = fResourceProvider ? LazyInstantiationType::kSingleUse | 
 |                                                        : LazyInstantiationType::kMultipleUse; | 
 |     return this->createLazyProxy(std::move(callback), format, desc, origin, mipMapped, surfaceFlags, | 
 |                                  fit, budgeted, lazyType); | 
 | } | 
 |  | 
 | sk_sp<GrTextureProxy> GrProxyProvider::createLazyProxy(LazyInstantiateCallback&& callback, | 
 |                                                        const GrBackendFormat& format, | 
 |                                                        const GrSurfaceDesc& desc, | 
 |                                                        GrSurfaceOrigin origin, | 
 |                                                        GrMipMapped mipMapped, | 
 |                                                        GrInternalSurfaceFlags surfaceFlags, | 
 |                                                        SkBackingFit fit, | 
 |                                                        SkBudgeted budgeted, | 
 |                                                        LazyInstantiationType lazyType) { | 
 |     SkASSERT((desc.fWidth <= 0 && desc.fHeight <= 0) || | 
 |              (desc.fWidth > 0 && desc.fHeight > 0)); | 
 |  | 
 |     if (desc.fWidth > fCaps->maxTextureSize() || desc.fHeight > fCaps->maxTextureSize()) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |  | 
 | #ifdef SK_DEBUG | 
 |     if (SkToBool(kRenderTarget_GrSurfaceFlag & desc.fFlags)) { | 
 |         if (SkToBool(surfaceFlags & GrInternalSurfaceFlags::kMixedSampled)) { | 
 |             SkASSERT(fCaps->usesMixedSamples() && desc.fSampleCnt > 1); | 
 |         } | 
 |     } | 
 | #endif | 
 |  | 
 |     return sk_sp<GrTextureProxy>( | 
 |             SkToBool(kRenderTarget_GrSurfaceFlag & desc.fFlags) | 
 |                     ? new GrTextureRenderTargetProxy(std::move(callback), lazyType, format, desc, | 
 |                                                      origin, mipMapped, fit, budgeted, surfaceFlags) | 
 |                     : new GrTextureProxy(std::move(callback), lazyType, format, desc, origin, | 
 |                                          mipMapped, fit, budgeted, surfaceFlags)); | 
 | } | 
 |  | 
 | sk_sp<GrRenderTargetProxy> GrProxyProvider::createLazyRenderTargetProxy( | 
 |         LazyInstantiateCallback&& callback, const GrBackendFormat& format, | 
 |         const GrSurfaceDesc& desc, GrSurfaceOrigin origin, GrInternalSurfaceFlags surfaceFlags, | 
 |         const TextureInfo* textureInfo, SkBackingFit fit, SkBudgeted budgeted) { | 
 |     SkASSERT((desc.fWidth <= 0 && desc.fHeight <= 0) || | 
 |              (desc.fWidth > 0 && desc.fHeight > 0)); | 
 |  | 
 |     if (desc.fWidth > fCaps->maxRenderTargetSize() || desc.fHeight > fCaps->maxRenderTargetSize()) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     SkASSERT(SkToBool(kRenderTarget_GrSurfaceFlag & desc.fFlags)); | 
 |  | 
 | #ifdef SK_DEBUG | 
 |     if (SkToBool(surfaceFlags & GrInternalSurfaceFlags::kMixedSampled)) { | 
 |         SkASSERT(fCaps->usesMixedSamples() && desc.fSampleCnt > 1); | 
 |     } | 
 | #endif | 
 |  | 
 |     using LazyInstantiationType = GrSurfaceProxy::LazyInstantiationType; | 
 |     // For non-ddl draws always make lazy proxy's single use. | 
 |     LazyInstantiationType lazyType = fResourceProvider ? LazyInstantiationType::kSingleUse | 
 |                                                        : LazyInstantiationType::kMultipleUse; | 
 |  | 
 |     if (textureInfo) { | 
 |         return sk_sp<GrRenderTargetProxy>(new GrTextureRenderTargetProxy( | 
 |                 std::move(callback), lazyType, format, desc, origin, textureInfo->fMipMapped, | 
 |                 fit, budgeted, surfaceFlags)); | 
 |     } | 
 |  | 
 |     return sk_sp<GrRenderTargetProxy>(new GrRenderTargetProxy( | 
 |             std::move(callback), lazyType, format, desc, origin, fit, budgeted, surfaceFlags)); | 
 | } | 
 |  | 
 | sk_sp<GrTextureProxy> GrProxyProvider::MakeFullyLazyProxy(LazyInstantiateCallback&& callback, | 
 |                                                           const GrBackendFormat& format, | 
 |                                                           Renderable renderable, | 
 |                                                           GrSurfaceOrigin origin, | 
 |                                                           GrPixelConfig config, | 
 |                                                           const GrCaps& caps) { | 
 |     GrSurfaceDesc desc; | 
 |     GrInternalSurfaceFlags surfaceFlags = GrInternalSurfaceFlags::kNoPendingIO; | 
 |     if (Renderable::kYes == renderable) { | 
 |         desc.fFlags = kRenderTarget_GrSurfaceFlag; | 
 |     } | 
 |     desc.fWidth = -1; | 
 |     desc.fHeight = -1; | 
 |     desc.fConfig = config; | 
 |     desc.fSampleCnt = 1; | 
 |  | 
 |     return sk_sp<GrTextureProxy>( | 
 |             (Renderable::kYes == renderable) | 
 |                     ? new GrTextureRenderTargetProxy( | 
 |                               std::move(callback), LazyInstantiationType::kSingleUse, format, desc, | 
 |                               origin, GrMipMapped::kNo, SkBackingFit::kApprox, SkBudgeted::kYes, | 
 |                               surfaceFlags) | 
 |                     : new GrTextureProxy(std::move(callback), LazyInstantiationType::kSingleUse, | 
 |                                          format, desc, origin, GrMipMapped::kNo, | 
 |                                          SkBackingFit::kApprox, SkBudgeted::kYes, surfaceFlags)); | 
 | } | 
 |  | 
 | bool GrProxyProvider::IsFunctionallyExact(GrSurfaceProxy* proxy) { | 
 |     const bool isInstantiated = proxy->isInstantiated(); | 
 |     // A proxy is functionally exact if: | 
 |     //   it is exact (obvs) | 
 |     //   when it is instantiated it will be exact (i.e., power of two dimensions) | 
 |     //   it is already instantiated and the proxy covers the entire backing surface | 
 |     return proxy->priv().isExact() || | 
 |            (!isInstantiated && SkIsPow2(proxy->width()) && SkIsPow2(proxy->height())) || | 
 |            (isInstantiated && proxy->worstCaseWidth() == proxy->width() && | 
 |                               proxy->worstCaseHeight() == proxy->height()); | 
 | } | 
 |  | 
 | void GrProxyProvider::processInvalidUniqueKey(const GrUniqueKey& key, GrTextureProxy* proxy, | 
 |                                               InvalidateGPUResource invalidateGPUResource) { | 
 |     SkASSERT(key.isValid()); | 
 |  | 
 |     if (!proxy) { | 
 |         proxy = fUniquelyKeyedProxies.find(key); | 
 |     } | 
 |     SkASSERT(!proxy || proxy->getUniqueKey() == key); | 
 |  | 
 |     // Locate the corresponding GrGpuResource (if it needs to be invalidated) before clearing the | 
 |     // proxy's unique key. We must do it in this order because 'key' may alias the proxy's key. | 
 |     sk_sp<GrGpuResource> invalidGpuResource; | 
 |     if (InvalidateGPUResource::kYes == invalidateGPUResource) { | 
 |         if (proxy && proxy->isInstantiated()) { | 
 |             invalidGpuResource = sk_ref_sp(proxy->peekSurface()); | 
 |         } | 
 |         if (!invalidGpuResource && fResourceProvider) { | 
 |             invalidGpuResource = fResourceProvider->findByUniqueKey<GrGpuResource>(key); | 
 |         } | 
 |         SkASSERT(!invalidGpuResource || invalidGpuResource->getUniqueKey() == key); | 
 |     } | 
 |  | 
 |     // Note: this method is called for the whole variety of GrGpuResources so often 'key' | 
 |     // will not be in 'fUniquelyKeyedProxies'. | 
 |     if (proxy) { | 
 |         fUniquelyKeyedProxies.remove(key); | 
 |         proxy->cacheAccess().clearUniqueKey(); | 
 |     } | 
 |  | 
 |     if (invalidGpuResource) { | 
 |         invalidGpuResource->resourcePriv().removeUniqueKey(); | 
 |     } | 
 | } | 
 |  | 
 | void GrProxyProvider::orphanAllUniqueKeys() { | 
 |     UniquelyKeyedProxyHash::Iter iter(&fUniquelyKeyedProxies); | 
 |     for (UniquelyKeyedProxyHash::Iter iter(&fUniquelyKeyedProxies); !iter.done(); ++iter) { | 
 |         GrTextureProxy& tmp = *iter; | 
 |  | 
 |         tmp.fProxyProvider = nullptr; | 
 |     } | 
 | } | 
 |  | 
 | void GrProxyProvider::removeAllUniqueKeys() { | 
 |     UniquelyKeyedProxyHash::Iter iter(&fUniquelyKeyedProxies); | 
 |     for (UniquelyKeyedProxyHash::Iter iter(&fUniquelyKeyedProxies); !iter.done(); ++iter) { | 
 |         GrTextureProxy& tmp = *iter; | 
 |  | 
 |         this->processInvalidUniqueKey(tmp.getUniqueKey(), &tmp, InvalidateGPUResource::kNo); | 
 |     } | 
 |     SkASSERT(!fUniquelyKeyedProxies.count()); | 
 | } |