| /* | |
| * Copyright 2016 Google Inc. | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "GrTextureAdjuster.h" | |
| #include "GrColorSpaceXform.h" | |
| #include "GrContext.h" | |
| #include "GrContextPriv.h" | |
| #include "GrGpu.h" | |
| #include "GrProxyProvider.h" | |
| #include "SkGr.h" | |
| GrTextureAdjuster::GrTextureAdjuster(GrContext* context, sk_sp<GrTextureProxy> original, | |
| SkAlphaType alphaType, | |
| uint32_t uniqueID, | |
| SkColorSpace* cs) | |
| : INHERITED(context, original->width(), original->height(), | |
| GrPixelConfigIsAlphaOnly(original->config())) | |
| , fOriginal(std::move(original)) | |
| , fAlphaType(alphaType) | |
| , fColorSpace(cs) | |
| , fUniqueID(uniqueID) {} | |
| void GrTextureAdjuster::makeCopyKey(const CopyParams& params, GrUniqueKey* copyKey, | |
| SkColorSpace* dstColorSpace) { | |
| // Destination color space is irrelevant - we already have a texture so we're just sub-setting | |
| GrUniqueKey baseKey; | |
| GrMakeKeyFromImageID(&baseKey, fUniqueID, SkIRect::MakeWH(this->width(), this->height())); | |
| MakeCopyKeyFromOrigKey(baseKey, params, copyKey); | |
| } | |
| void GrTextureAdjuster::didCacheCopy(const GrUniqueKey& copyKey, uint32_t contextUniqueID) { | |
| // We don't currently have a mechanism for notifications on Images! | |
| } | |
| sk_sp<GrTextureProxy> GrTextureAdjuster::refTextureProxyCopy(const CopyParams& copyParams, | |
| bool willBeMipped) { | |
| GrProxyProvider* proxyProvider = fContext->contextPriv().proxyProvider(); | |
| GrUniqueKey key; | |
| this->makeCopyKey(copyParams, &key, nullptr); | |
| sk_sp<GrTextureProxy> cachedCopy; | |
| if (key.isValid()) { | |
| cachedCopy = proxyProvider->findOrCreateProxyByUniqueKey(key, | |
| this->originalProxy()->origin()); | |
| if (cachedCopy && (!willBeMipped || GrMipMapped::kYes == cachedCopy->mipMapped())) { | |
| return cachedCopy; | |
| } | |
| } | |
| sk_sp<GrTextureProxy> proxy = this->originalProxyRef(); | |
| sk_sp<GrTextureProxy> copy = CopyOnGpu(fContext, std::move(proxy), copyParams, willBeMipped); | |
| if (copy) { | |
| if (key.isValid()) { | |
| SkASSERT(copy->origin() == this->originalProxy()->origin()); | |
| if (cachedCopy) { | |
| SkASSERT(GrMipMapped::kYes == copy->mipMapped() && | |
| GrMipMapped::kNo == cachedCopy->mipMapped()); | |
| // If we had a cachedProxy, that means there already is a proxy in the cache which | |
| // matches the key, but it does not have mip levels and we require them. Thus we | |
| // must remove the unique key from that proxy. | |
| proxyProvider->removeUniqueKeyFromProxy(key, cachedCopy.get()); | |
| } | |
| proxyProvider->assignUniqueKeyToProxy(key, copy.get()); | |
| this->didCacheCopy(key, proxyProvider->contextUniqueID()); | |
| } | |
| } | |
| return copy; | |
| } | |
| sk_sp<GrTextureProxy> GrTextureAdjuster::onRefTextureProxyForParams( | |
| const GrSamplerState& params, | |
| SkColorSpace* dstColorSpace, | |
| sk_sp<SkColorSpace>* texColorSpace, | |
| bool willBeMipped, | |
| SkScalar scaleAdjust[2]) { | |
| sk_sp<GrTextureProxy> proxy = this->originalProxyRef(); | |
| CopyParams copyParams; | |
| if (!fContext) { | |
| // The texture was abandoned. | |
| return nullptr; | |
| } | |
| if (texColorSpace) { | |
| *texColorSpace = sk_ref_sp(fColorSpace); | |
| } | |
| SkASSERT(this->width() <= fContext->contextPriv().caps()->maxTextureSize() && | |
| this->height() <= fContext->contextPriv().caps()->maxTextureSize()); | |
| bool needsCopyForMipsOnly = false; | |
| if (!params.isRepeated() || | |
| !GrGpu::IsACopyNeededForRepeatWrapMode(fContext->contextPriv().caps(), proxy.get(), | |
| proxy->width(), proxy->height(), params.filter(), | |
| ©Params, scaleAdjust)) { | |
| needsCopyForMipsOnly = GrGpu::IsACopyNeededForMips(fContext->contextPriv().caps(), | |
| proxy.get(), params.filter(), | |
| ©Params); | |
| if (!needsCopyForMipsOnly) { | |
| return proxy; | |
| } | |
| } | |
| sk_sp<GrTextureProxy> result = this->refTextureProxyCopy(copyParams, willBeMipped); | |
| if (!result && needsCopyForMipsOnly) { | |
| // If we were unable to make a copy and we only needed a copy for mips, then we will return | |
| // the source texture here and require that the GPU backend is able to fall back to using | |
| // bilerp if mips are required. | |
| return this->originalProxyRef(); | |
| } | |
| return result; | |
| } | |
| std::unique_ptr<GrFragmentProcessor> GrTextureAdjuster::createFragmentProcessor( | |
| const SkMatrix& origTextureMatrix, | |
| const SkRect& constraintRect, | |
| FilterConstraint filterConstraint, | |
| bool coordsLimitedToConstraintRect, | |
| const GrSamplerState::Filter* filterOrNullForBicubic, | |
| SkColorSpace* dstColorSpace) { | |
| SkMatrix textureMatrix = origTextureMatrix; | |
| SkRect domain; | |
| GrSamplerState samplerState; | |
| if (filterOrNullForBicubic) { | |
| samplerState.setFilterMode(*filterOrNullForBicubic); | |
| } | |
| SkScalar scaleAdjust[2] = { 1.0f, 1.0f }; | |
| sk_sp<GrTextureProxy> proxy( | |
| this->refTextureProxyForParams(samplerState, nullptr, nullptr, scaleAdjust)); | |
| if (!proxy) { | |
| return nullptr; | |
| } | |
| // If we made a copy then we only copied the contentArea, in which case the new texture is all | |
| // content. | |
| if (proxy.get() != this->originalProxy()) { | |
| textureMatrix.postScale(scaleAdjust[0], scaleAdjust[1]); | |
| } | |
| DomainMode domainMode = | |
| DetermineDomainMode(constraintRect, filterConstraint, coordsLimitedToConstraintRect, | |
| proxy.get(), filterOrNullForBicubic, &domain); | |
| if (kTightCopy_DomainMode == domainMode) { | |
| // TODO: Copy the texture and adjust the texture matrix (both parts need to consider | |
| // non-int constraint rect) | |
| // For now: treat as bilerp and ignore what goes on above level 0. | |
| // We only expect MIP maps to require a tight copy. | |
| SkASSERT(filterOrNullForBicubic && | |
| GrSamplerState::Filter::kMipMap == *filterOrNullForBicubic); | |
| static const GrSamplerState::Filter kBilerp = GrSamplerState::Filter::kBilerp; | |
| domainMode = | |
| DetermineDomainMode(constraintRect, filterConstraint, coordsLimitedToConstraintRect, | |
| proxy.get(), &kBilerp, &domain); | |
| SkASSERT(kTightCopy_DomainMode != domainMode); | |
| } | |
| SkASSERT(kNoDomain_DomainMode == domainMode || | |
| (domain.fLeft <= domain.fRight && domain.fTop <= domain.fBottom)); | |
| auto fp = CreateFragmentProcessorForDomainAndFilter(std::move(proxy), textureMatrix, | |
| domainMode, domain, filterOrNullForBicubic); | |
| return GrColorSpaceXformEffect::Make(std::move(fp), fColorSpace, fAlphaType, dstColorSpace); | |
| } |