| /* |
| * 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 "include/private/GrRecordingContext.h" |
| #include "src/gpu/GrColorSpaceXform.h" |
| #include "src/gpu/GrGpu.h" |
| #include "src/gpu/GrProxyProvider.h" |
| #include "src/gpu/GrRecordingContextPriv.h" |
| #include "src/gpu/GrTextureAdjuster.h" |
| #include "src/gpu/SkGr.h" |
| |
| GrTextureAdjuster::GrTextureAdjuster(GrRecordingContext* context, |
| GrSurfaceProxyView original, |
| const GrColorInfo& colorInfo, |
| uint32_t uniqueID, |
| bool useDecal) |
| : INHERITED(context, {colorInfo, original.proxy()->dimensions()}, useDecal) |
| , fOriginal(std::move(original)) |
| , fUniqueID(uniqueID) {} |
| |
| void GrTextureAdjuster::makeCopyKey(const CopyParams& params, GrUniqueKey* copyKey) { |
| // Destination color space is irrelevant - we already have a texture so we're just sub-setting |
| GrUniqueKey baseKey; |
| GrMakeKeyFromImageID(&baseKey, fUniqueID, SkIRect::MakeSize(this->dimensions())); |
| MakeCopyKeyFromOrigKey(baseKey, params, copyKey); |
| } |
| |
| void GrTextureAdjuster::didCacheCopy(const GrUniqueKey& copyKey, uint32_t contextUniqueID) { |
| // We don't currently have a mechanism for notifications on Images! |
| } |
| |
| GrSurfaceProxyView GrTextureAdjuster::copy(const CopyParams& copyParams, bool willBeMipped, |
| bool copyForMipsOnly) { |
| GrProxyProvider* proxyProvider = this->context()->priv().proxyProvider(); |
| |
| GrUniqueKey key; |
| this->makeCopyKey(copyParams, &key); |
| sk_sp<GrTextureProxy> cachedCopy; |
| const GrSurfaceProxyView& originalView = this->originalProxyView(); |
| if (key.isValid()) { |
| cachedCopy = proxyProvider->findOrCreateProxyByUniqueKey(key, this->colorType(), |
| originalView.origin()); |
| if (cachedCopy && (!willBeMipped || GrMipMapped::kYes == cachedCopy->mipMapped())) { |
| // TODO: Once we no longer use CopyOnGpu which can fallback to arbitrary formats and |
| // colorTypes, we can use the swizzle of the originalView. |
| GrSwizzle swizzle = cachedCopy->textureSwizzleDoNotUse(); |
| return GrSurfaceProxyView(std::move(cachedCopy), originalView.origin(), swizzle); |
| } |
| } |
| |
| GrSurfaceProxyView copyView; |
| if (copyForMipsOnly) { |
| copyView = GrCopyBaseMipMapToTextureProxy(this->context(), originalView.proxy(), |
| originalView.origin(), this->colorType()); |
| } else { |
| copyView = CopyOnGpu(this->context(), this->originalProxyViewRef(), this->colorType(), |
| copyParams, willBeMipped); |
| } |
| if (copyView.proxy()) { |
| if (key.isValid()) { |
| SkASSERT(copyView.origin() == originalView.origin()); |
| if (cachedCopy) { |
| SkASSERT(GrMipMapped::kYes == copyView.asTextureProxy()->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. |
| SkASSERT(cachedCopy->getUniqueKey() == key); |
| proxyProvider->removeUniqueKeyFromProxy(cachedCopy.get()); |
| } |
| proxyProvider->assignUniqueKeyToProxy(key, copyView.asTextureProxy()); |
| this->didCacheCopy(key, proxyProvider->contextID()); |
| } |
| } |
| return copyView; |
| } |
| |
| GrSurfaceProxyView GrTextureAdjuster::onRefTextureProxyViewForParams(GrSamplerState params, |
| bool willBeMipped, |
| SkScalar scaleAdjust[2]) { |
| if (this->context()->priv().abandoned()) { |
| // The texture was abandoned. |
| return {}; |
| } |
| |
| SkASSERT(this->width() <= this->context()->priv().caps()->maxTextureSize() && |
| this->height() <= this->context()->priv().caps()->maxTextureSize()); |
| |
| GrSurfaceProxyView view = this->originalProxyViewRef(); |
| GrTextureProxy* texProxy = view.asTextureProxy(); |
| SkASSERT(texProxy); |
| CopyParams copyParams; |
| |
| bool needsCopyForMipsOnly = false; |
| if (!params.isRepeated() || |
| !GrGpu::IsACopyNeededForRepeatWrapMode(this->context()->priv().caps(), texProxy, |
| texProxy->dimensions(), params.filter(), ©Params, |
| scaleAdjust)) { |
| needsCopyForMipsOnly = GrGpu::IsACopyNeededForMips(this->context()->priv().caps(), |
| texProxy, params.filter(), |
| ©Params); |
| if (!needsCopyForMipsOnly) { |
| return view; |
| } |
| } |
| |
| GrSurfaceProxyView result = this->copy(copyParams, willBeMipped, needsCopyForMipsOnly); |
| if (!result.proxy() && 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 view; |
| } |
| SkASSERT(result.asTextureProxy()); |
| return result; |
| } |
| |
| std::unique_ptr<GrFragmentProcessor> GrTextureAdjuster::createFragmentProcessor( |
| const SkMatrix& origTextureMatrix, |
| const SkRect& constraintRect, |
| FilterConstraint filterConstraint, |
| bool coordsLimitedToConstraintRect, |
| const GrSamplerState::Filter* filterOrNullForBicubic) { |
| SkMatrix textureMatrix = origTextureMatrix; |
| |
| SkScalar scaleAdjust[2] = { 1.0f, 1.0f }; |
| GrSurfaceProxyView view = this->viewForParams(filterOrNullForBicubic, scaleAdjust); |
| if (!view.proxy()) { |
| return nullptr; |
| } |
| SkASSERT(view.asTextureProxy()); |
| // If we made a copy then we only copied the contentArea, in which case the new texture is all |
| // content. |
| if (view.proxy() != this->originalProxyView().proxy()) { |
| textureMatrix.postScale(scaleAdjust[0], scaleAdjust[1]); |
| } |
| |
| SkRect domain; |
| DomainMode domainMode = |
| DetermineDomainMode(constraintRect, filterConstraint, coordsLimitedToConstraintRect, |
| view.proxy(), 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, |
| view.proxy(), &kBilerp, &domain); |
| SkASSERT(kTightCopy_DomainMode != domainMode); |
| } |
| SkASSERT(kNoDomain_DomainMode == domainMode || |
| (domain.fLeft <= domain.fRight && domain.fTop <= domain.fBottom)); |
| return this->createFragmentProcessorForDomainAndFilter( |
| std::move(view), textureMatrix, domainMode, domain, filterOrNullForBicubic); |
| } |