1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2017 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h" 9cb93a386Sopenharmony_ci#include "include/gpu/GrRecordingContext.h" 10cb93a386Sopenharmony_ci#include "src/core/SkMessageBus.h" 11cb93a386Sopenharmony_ci#include "src/gpu/GrBackendTextureImageGenerator.h" 12cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h" 13cb93a386Sopenharmony_ci#include "src/gpu/GrGpu.h" 14cb93a386Sopenharmony_ci#include "src/gpu/GrProxyProvider.h" 15cb93a386Sopenharmony_ci#include "src/gpu/GrRecordingContextPriv.h" 16cb93a386Sopenharmony_ci#include "src/gpu/GrResourceCache.h" 17cb93a386Sopenharmony_ci#include "src/gpu/GrResourceProvider.h" 18cb93a386Sopenharmony_ci#include "src/gpu/GrResourceProviderPriv.h" 19cb93a386Sopenharmony_ci#include "src/gpu/GrSemaphore.h" 20cb93a386Sopenharmony_ci#include "src/gpu/GrTexture.h" 21cb93a386Sopenharmony_ci#include "src/gpu/GrTextureProxyPriv.h" 22cb93a386Sopenharmony_ci#include "src/gpu/SkGr.h" 23cb93a386Sopenharmony_ci#include "src/gpu/gl/GrGLTexture.h" 24cb93a386Sopenharmony_ci 25cb93a386Sopenharmony_ciGrBackendTextureImageGenerator::RefHelper::RefHelper( 26cb93a386Sopenharmony_ci GrTexture* texture, 27cb93a386Sopenharmony_ci GrDirectContext::DirectContextID owningContextID, 28cb93a386Sopenharmony_ci std::unique_ptr<GrSemaphore> semaphore) 29cb93a386Sopenharmony_ci : fOriginalTexture(texture) 30cb93a386Sopenharmony_ci , fOwningContextID(owningContextID) 31cb93a386Sopenharmony_ci , fBorrowingContextReleaseProc(nullptr) 32cb93a386Sopenharmony_ci , fSemaphore(std::move(semaphore)) {} 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_ciGrBackendTextureImageGenerator::RefHelper::~RefHelper() { 35cb93a386Sopenharmony_ci SkASSERT(!fBorrowingContextID.isValid()); 36cb93a386Sopenharmony_ci 37cb93a386Sopenharmony_ci // Generator has been freed, and no one is borrowing the texture. Notify the original cache 38cb93a386Sopenharmony_ci // that it can free the last ref, so it happens on the correct thread. 39cb93a386Sopenharmony_ci GrTextureFreedMessage msg { fOriginalTexture, fOwningContextID }; 40cb93a386Sopenharmony_ci SkMessageBus<GrTextureFreedMessage, GrDirectContext::DirectContextID>::Post(msg); 41cb93a386Sopenharmony_ci} 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_cistd::unique_ptr<SkImageGenerator> 44cb93a386Sopenharmony_ciGrBackendTextureImageGenerator::Make(sk_sp<GrTexture> texture, GrSurfaceOrigin origin, 45cb93a386Sopenharmony_ci std::unique_ptr<GrSemaphore> semaphore, SkColorType colorType, 46cb93a386Sopenharmony_ci SkAlphaType alphaType, sk_sp<SkColorSpace> colorSpace) { 47cb93a386Sopenharmony_ci GrDirectContext* dContext = texture->getContext(); 48cb93a386Sopenharmony_ci 49cb93a386Sopenharmony_ci // Attach our texture to this context's resource cache. This ensures that deletion will happen 50cb93a386Sopenharmony_ci // in the correct thread/context. This adds the only ref to the texture that will persist from 51cb93a386Sopenharmony_ci // this point. That ref will be released when the generator's RefHelper is freed. 52cb93a386Sopenharmony_ci dContext->priv().getResourceCache()->insertDelayedTextureUnref(texture.get()); 53cb93a386Sopenharmony_ci 54cb93a386Sopenharmony_ci GrBackendTexture backendTexture = texture->getBackendTexture(); 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_ci if (!dContext->priv().caps()->areColorTypeAndFormatCompatible( 57cb93a386Sopenharmony_ci SkColorTypeToGrColorType(colorType), backendTexture.getBackendFormat())) { 58cb93a386Sopenharmony_ci return nullptr; 59cb93a386Sopenharmony_ci } 60cb93a386Sopenharmony_ci 61cb93a386Sopenharmony_ci SkImageInfo info = SkImageInfo::Make(texture->width(), texture->height(), colorType, alphaType, 62cb93a386Sopenharmony_ci std::move(colorSpace)); 63cb93a386Sopenharmony_ci return std::unique_ptr<SkImageGenerator>(new GrBackendTextureImageGenerator( 64cb93a386Sopenharmony_ci info, texture.get(), origin, dContext->directContextID(), 65cb93a386Sopenharmony_ci std::move(semaphore), backendTexture)); 66cb93a386Sopenharmony_ci} 67cb93a386Sopenharmony_ci 68cb93a386Sopenharmony_ciGrBackendTextureImageGenerator::GrBackendTextureImageGenerator( 69cb93a386Sopenharmony_ci const SkImageInfo& info, 70cb93a386Sopenharmony_ci GrTexture* texture, 71cb93a386Sopenharmony_ci GrSurfaceOrigin origin, 72cb93a386Sopenharmony_ci GrDirectContext::DirectContextID owningContextID, 73cb93a386Sopenharmony_ci std::unique_ptr<GrSemaphore> semaphore, 74cb93a386Sopenharmony_ci const GrBackendTexture& backendTex) 75cb93a386Sopenharmony_ci : INHERITED(info) 76cb93a386Sopenharmony_ci , fRefHelper(new RefHelper(texture, owningContextID, std::move(semaphore))) 77cb93a386Sopenharmony_ci , fBackendTexture(backendTex) 78cb93a386Sopenharmony_ci , fSurfaceOrigin(origin) {} 79cb93a386Sopenharmony_ci 80cb93a386Sopenharmony_ciGrBackendTextureImageGenerator::~GrBackendTextureImageGenerator() { 81cb93a386Sopenharmony_ci fRefHelper->unref(); 82cb93a386Sopenharmony_ci} 83cb93a386Sopenharmony_ci 84cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////////////////////////// 85cb93a386Sopenharmony_ci 86cb93a386Sopenharmony_civoid GrBackendTextureImageGenerator::ReleaseRefHelper_TextureReleaseProc(void* ctx) { 87cb93a386Sopenharmony_ci RefHelper* refHelper = static_cast<RefHelper*>(ctx); 88cb93a386Sopenharmony_ci SkASSERT(refHelper); 89cb93a386Sopenharmony_ci 90cb93a386Sopenharmony_ci refHelper->fBorrowingContextReleaseProc = nullptr; 91cb93a386Sopenharmony_ci refHelper->fBorrowingContextID.makeInvalid(); 92cb93a386Sopenharmony_ci refHelper->unref(); 93cb93a386Sopenharmony_ci} 94cb93a386Sopenharmony_ci 95cb93a386Sopenharmony_ciGrSurfaceProxyView GrBackendTextureImageGenerator::onGenerateTexture( 96cb93a386Sopenharmony_ci GrRecordingContext* rContext, 97cb93a386Sopenharmony_ci const SkImageInfo& info, 98cb93a386Sopenharmony_ci const SkIPoint& origin, 99cb93a386Sopenharmony_ci GrMipmapped mipMapped, 100cb93a386Sopenharmony_ci GrImageTexGenPolicy texGenPolicy) { 101cb93a386Sopenharmony_ci SkASSERT(rContext); 102cb93a386Sopenharmony_ci 103cb93a386Sopenharmony_ci // We currently limit GrBackendTextureImageGenerators to direct contexts since 104cb93a386Sopenharmony_ci // only Flutter uses them and doesn't use recording/DDL contexts. Ideally, the 105cb93a386Sopenharmony_ci // cross context texture functionality can be subsumed by the thread-safe cache 106cb93a386Sopenharmony_ci // working with utility contexts. 107cb93a386Sopenharmony_ci auto dContext = rContext->asDirectContext(); 108cb93a386Sopenharmony_ci if (!dContext) { 109cb93a386Sopenharmony_ci return {}; 110cb93a386Sopenharmony_ci } 111cb93a386Sopenharmony_ci 112cb93a386Sopenharmony_ci if (dContext->backend() != fBackendTexture.backend()) { 113cb93a386Sopenharmony_ci return {}; 114cb93a386Sopenharmony_ci } 115cb93a386Sopenharmony_ci if (info.colorType() != this->getInfo().colorType()) { 116cb93a386Sopenharmony_ci return {}; 117cb93a386Sopenharmony_ci } 118cb93a386Sopenharmony_ci 119cb93a386Sopenharmony_ci auto proxyProvider = dContext->priv().proxyProvider(); 120cb93a386Sopenharmony_ci 121cb93a386Sopenharmony_ci fBorrowingMutex.acquire(); 122cb93a386Sopenharmony_ci sk_sp<GrRefCntedCallback> releaseProcHelper; 123cb93a386Sopenharmony_ci if (fRefHelper->fBorrowingContextID.isValid()) { 124cb93a386Sopenharmony_ci if (fRefHelper->fBorrowingContextID != dContext->directContextID()) { 125cb93a386Sopenharmony_ci fBorrowingMutex.release(); 126cb93a386Sopenharmony_ci rContext->priv().printWarningMessage( 127cb93a386Sopenharmony_ci "GrBackendTextureImageGenerator: Trying to use texture on two GrContexts!\n"); 128cb93a386Sopenharmony_ci return {}; 129cb93a386Sopenharmony_ci } else { 130cb93a386Sopenharmony_ci SkASSERT(fRefHelper->fBorrowingContextReleaseProc); 131cb93a386Sopenharmony_ci // Ref the release proc to be held by the proxy we make below 132cb93a386Sopenharmony_ci releaseProcHelper = sk_ref_sp(fRefHelper->fBorrowingContextReleaseProc); 133cb93a386Sopenharmony_ci } 134cb93a386Sopenharmony_ci } else { 135cb93a386Sopenharmony_ci SkASSERT(!fRefHelper->fBorrowingContextReleaseProc); 136cb93a386Sopenharmony_ci // The ref we add to fRefHelper here will be passed into and owned by the 137cb93a386Sopenharmony_ci // GrRefCntedCallback. 138cb93a386Sopenharmony_ci fRefHelper->ref(); 139cb93a386Sopenharmony_ci releaseProcHelper = 140cb93a386Sopenharmony_ci GrRefCntedCallback::Make(ReleaseRefHelper_TextureReleaseProc, fRefHelper); 141cb93a386Sopenharmony_ci fRefHelper->fBorrowingContextReleaseProc = releaseProcHelper.get(); 142cb93a386Sopenharmony_ci } 143cb93a386Sopenharmony_ci fRefHelper->fBorrowingContextID = dContext->directContextID(); 144cb93a386Sopenharmony_ci if (!fRefHelper->fBorrowedTextureKey.isValid()) { 145cb93a386Sopenharmony_ci static const auto kDomain = GrUniqueKey::GenerateDomain(); 146cb93a386Sopenharmony_ci GrUniqueKey::Builder builder(&fRefHelper->fBorrowedTextureKey, kDomain, 1); 147cb93a386Sopenharmony_ci builder[0] = this->uniqueID(); 148cb93a386Sopenharmony_ci } 149cb93a386Sopenharmony_ci fBorrowingMutex.release(); 150cb93a386Sopenharmony_ci 151cb93a386Sopenharmony_ci SkASSERT(fRefHelper->fBorrowingContextID == dContext->directContextID()); 152cb93a386Sopenharmony_ci 153cb93a386Sopenharmony_ci GrBackendFormat backendFormat = fBackendTexture.getBackendFormat(); 154cb93a386Sopenharmony_ci SkASSERT(backendFormat.isValid()); 155cb93a386Sopenharmony_ci 156cb93a386Sopenharmony_ci GrColorType grColorType = SkColorTypeToGrColorType(info.colorType()); 157cb93a386Sopenharmony_ci 158cb93a386Sopenharmony_ci GrMipmapped textureIsMipMapped = fBackendTexture.hasMipmaps() ? GrMipmapped::kYes 159cb93a386Sopenharmony_ci : GrMipmapped::kNo; 160cb93a386Sopenharmony_ci 161cb93a386Sopenharmony_ci // Ganesh assumes that, when wrapping a mipmapped backend texture from a client, that its 162cb93a386Sopenharmony_ci // mipmaps are fully fleshed out. 163cb93a386Sopenharmony_ci GrMipmapStatus mipmapStatus = fBackendTexture.hasMipmaps() 164cb93a386Sopenharmony_ci ? GrMipmapStatus::kValid : GrMipmapStatus::kNotAllocated; 165cb93a386Sopenharmony_ci 166cb93a386Sopenharmony_ci GrSwizzle readSwizzle = dContext->priv().caps()->getReadSwizzle(backendFormat, grColorType); 167cb93a386Sopenharmony_ci 168cb93a386Sopenharmony_ci // Must make copies of member variables to capture in the lambda since this image generator may 169cb93a386Sopenharmony_ci // be deleted before we actually execute the lambda. 170cb93a386Sopenharmony_ci sk_sp<GrTextureProxy> proxy = proxyProvider->createLazyProxy( 171cb93a386Sopenharmony_ci [refHelper = fRefHelper, releaseProcHelper, backendTexture = fBackendTexture]( 172cb93a386Sopenharmony_ci GrResourceProvider* resourceProvider, 173cb93a386Sopenharmony_ci const GrSurfaceProxy::LazySurfaceDesc&) -> GrSurfaceProxy::LazyCallbackResult { 174cb93a386Sopenharmony_ci if (refHelper->fSemaphore) { 175cb93a386Sopenharmony_ci resourceProvider->priv().gpu()->waitSemaphore(refHelper->fSemaphore.get()); 176cb93a386Sopenharmony_ci } 177cb93a386Sopenharmony_ci 178cb93a386Sopenharmony_ci // If a client re-draws the same image multiple times, the texture we return 179cb93a386Sopenharmony_ci // will be cached and re-used. If they draw a subset, though, we may be 180cb93a386Sopenharmony_ci // re-called. In that case, we want to re-use the borrowed texture we've 181cb93a386Sopenharmony_ci // previously created. 182cb93a386Sopenharmony_ci sk_sp<GrTexture> tex; 183cb93a386Sopenharmony_ci SkASSERT(refHelper->fBorrowedTextureKey.isValid()); 184cb93a386Sopenharmony_ci auto surf = resourceProvider->findByUniqueKey<GrSurface>( 185cb93a386Sopenharmony_ci refHelper->fBorrowedTextureKey); 186cb93a386Sopenharmony_ci if (surf) { 187cb93a386Sopenharmony_ci SkASSERT(surf->asTexture()); 188cb93a386Sopenharmony_ci tex = sk_ref_sp(surf->asTexture()); 189cb93a386Sopenharmony_ci } else { 190cb93a386Sopenharmony_ci // We just gained access to the texture. If we're on the original 191cb93a386Sopenharmony_ci // context, we could use the original texture, but we'd have no way of 192cb93a386Sopenharmony_ci // detecting that it's no longer in-use. So we always make a wrapped 193cb93a386Sopenharmony_ci // copy, where the release proc informs us that the context is done with 194cb93a386Sopenharmony_ci // it. This is unfortunate - we'll have two texture objects referencing 195cb93a386Sopenharmony_ci // the same GPU object. However, no client can ever see the original 196cb93a386Sopenharmony_ci // texture, so this should be safe. We make the texture uncacheable so 197cb93a386Sopenharmony_ci // that the release proc is called ASAP. 198cb93a386Sopenharmony_ci tex = resourceProvider->wrapBackendTexture( 199cb93a386Sopenharmony_ci backendTexture, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, 200cb93a386Sopenharmony_ci kRead_GrIOType); 201cb93a386Sopenharmony_ci if (!tex) { 202cb93a386Sopenharmony_ci return {}; 203cb93a386Sopenharmony_ci } 204cb93a386Sopenharmony_ci tex->setRelease(releaseProcHelper); 205cb93a386Sopenharmony_ci tex->resourcePriv().setUniqueKey(refHelper->fBorrowedTextureKey); 206cb93a386Sopenharmony_ci } 207cb93a386Sopenharmony_ci // We use keys to avoid re-wrapping the GrBackendTexture in a GrTexture. 208cb93a386Sopenharmony_ci // This is unrelated to the whatever SkImage key may be assigned to the 209cb93a386Sopenharmony_ci // proxy. 210cb93a386Sopenharmony_ci return {std::move(tex), true, GrSurfaceProxy::LazyInstantiationKeyMode::kUnsynced}; 211cb93a386Sopenharmony_ci }, 212cb93a386Sopenharmony_ci backendFormat, fBackendTexture.dimensions(), textureIsMipMapped, mipmapStatus, 213cb93a386Sopenharmony_ci GrInternalSurfaceFlags::kReadOnly, SkBackingFit::kExact, SkBudgeted::kNo, 214cb93a386Sopenharmony_ci GrProtected::kNo, GrSurfaceProxy::UseAllocator::kYes); 215cb93a386Sopenharmony_ci if (!proxy) { 216cb93a386Sopenharmony_ci return {}; 217cb93a386Sopenharmony_ci } 218cb93a386Sopenharmony_ci 219cb93a386Sopenharmony_ci if (texGenPolicy == GrImageTexGenPolicy::kDraw && origin.isZero() && 220cb93a386Sopenharmony_ci info.dimensions() == fBackendTexture.dimensions() && 221cb93a386Sopenharmony_ci (mipMapped == GrMipmapped::kNo || proxy->mipmapped() == GrMipmapped::kYes)) { 222cb93a386Sopenharmony_ci // If the caller wants the entire texture and we have the correct mip support, we're done 223cb93a386Sopenharmony_ci return GrSurfaceProxyView(std::move(proxy), fSurfaceOrigin, readSwizzle); 224cb93a386Sopenharmony_ci } else { 225cb93a386Sopenharmony_ci SkIRect subset = SkIRect::MakeXYWH(origin.fX, origin.fY, info.width(), info.height()); 226cb93a386Sopenharmony_ci 227cb93a386Sopenharmony_ci SkBudgeted budgeted = texGenPolicy == GrImageTexGenPolicy::kNew_Uncached_Unbudgeted 228cb93a386Sopenharmony_ci ? SkBudgeted::kNo 229cb93a386Sopenharmony_ci : SkBudgeted::kYes; 230cb93a386Sopenharmony_ci 231cb93a386Sopenharmony_ci auto copy = GrSurfaceProxy::Copy(dContext, 232cb93a386Sopenharmony_ci std::move(proxy), 233cb93a386Sopenharmony_ci fSurfaceOrigin, 234cb93a386Sopenharmony_ci mipMapped, 235cb93a386Sopenharmony_ci subset, 236cb93a386Sopenharmony_ci SkBackingFit::kExact, 237cb93a386Sopenharmony_ci budgeted); 238cb93a386Sopenharmony_ci return {std::move(copy), fSurfaceOrigin, readSwizzle}; 239cb93a386Sopenharmony_ci } 240cb93a386Sopenharmony_ci} 241