1 /* 2 * Copyright 2016 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 "GrTextureAdjuster.h" 9 #include "GrColorSpaceXform.h" 10 #include "GrContext.h" 11 #include "GrContextPriv.h" 12 #include "GrGpu.h" 13 #include "GrProxyProvider.h" 14 #include "SkGr.h" 15 16 GrTextureAdjuster::GrTextureAdjuster(GrContext* context, sk_sp<GrTextureProxy> original, 17 SkAlphaType alphaType, 18 uint32_t uniqueID, 19 SkColorSpace* cs) 20 : INHERITED(context, original->width(), original->height(), 21 GrPixelConfigIsAlphaOnly(original->config())) 22 , fOriginal(std::move(original)) 23 , fAlphaType(alphaType) 24 , fColorSpace(cs) 25 , fUniqueID(uniqueID) {} 26 27 void GrTextureAdjuster::makeCopyKey(const CopyParams& params, GrUniqueKey* copyKey) { 28 // Destination color space is irrelevant - we already have a texture so we're just sub-setting 29 GrUniqueKey baseKey; 30 GrMakeKeyFromImageID(&baseKey, fUniqueID, SkIRect::MakeWH(this->width(), this->height())); 31 MakeCopyKeyFromOrigKey(baseKey, params, copyKey); 32 } 33 34 void GrTextureAdjuster::didCacheCopy(const GrUniqueKey& copyKey, uint32_t contextUniqueID) { 35 // We don't currently have a mechanism for notifications on Images! 36 } 37 38 sk_sp<GrTextureProxy> GrTextureAdjuster::refTextureProxyCopy(const CopyParams& copyParams, 39 bool willBeMipped) { 40 GrProxyProvider* proxyProvider = fContext->contextPriv().proxyProvider(); 41 42 GrUniqueKey key; 43 this->makeCopyKey(copyParams, &key); 44 sk_sp<GrTextureProxy> cachedCopy; 45 if (key.isValid()) { 46 cachedCopy = proxyProvider->findOrCreateProxyByUniqueKey(key, 47 this->originalProxy()->origin()); 48 if (cachedCopy && (!willBeMipped || GrMipMapped::kYes == cachedCopy->mipMapped())) { 49 return cachedCopy; 50 } 51 } 52 53 sk_sp<GrTextureProxy> proxy = this->originalProxyRef(); 54 55 sk_sp<GrTextureProxy> copy = CopyOnGpu(fContext, std::move(proxy), copyParams, willBeMipped); 56 if (copy) { 57 if (key.isValid()) { 58 SkASSERT(copy->origin() == this->originalProxy()->origin()); 59 if (cachedCopy) { 60 SkASSERT(GrMipMapped::kYes == copy->mipMapped() && 61 GrMipMapped::kNo == cachedCopy->mipMapped()); 62 // If we had a cachedProxy, that means there already is a proxy in the cache which 63 // matches the key, but it does not have mip levels and we require them. Thus we 64 // must remove the unique key from that proxy. 65 SkASSERT(cachedCopy->getUniqueKey() == key); 66 proxyProvider->removeUniqueKeyFromProxy(cachedCopy.get()); 67 } 68 proxyProvider->assignUniqueKeyToProxy(key, copy.get()); 69 this->didCacheCopy(key, proxyProvider->contextUniqueID()); 70 } 71 } 72 return copy; 73 } 74 75 sk_sp<GrTextureProxy> GrTextureAdjuster::onRefTextureProxyForParams( 76 const GrSamplerState& params, 77 bool willBeMipped, 78 SkScalar scaleAdjust[2]) { 79 sk_sp<GrTextureProxy> proxy = this->originalProxyRef(); 80 CopyParams copyParams; 81 82 if (!fContext) { 83 // The texture was abandoned. 84 return nullptr; 85 } 86 87 SkASSERT(this->width() <= fContext->contextPriv().caps()->maxTextureSize() && 88 this->height() <= fContext->contextPriv().caps()->maxTextureSize()); 89 90 bool needsCopyForMipsOnly = false; 91 if (!params.isRepeated() || 92 !GrGpu::IsACopyNeededForRepeatWrapMode(fContext->contextPriv().caps(), proxy.get(), 93 proxy->width(), proxy->height(), params.filter(), 94 ©Params, scaleAdjust)) { 95 needsCopyForMipsOnly = GrGpu::IsACopyNeededForMips(fContext->contextPriv().caps(), 96 proxy.get(), params.filter(), 97 ©Params); 98 if (!needsCopyForMipsOnly) { 99 return proxy; 100 } 101 } 102 103 sk_sp<GrTextureProxy> result = this->refTextureProxyCopy(copyParams, willBeMipped); 104 if (!result && needsCopyForMipsOnly) { 105 // If we were unable to make a copy and we only needed a copy for mips, then we will return 106 // the source texture here and require that the GPU backend is able to fall back to using 107 // bilerp if mips are required. 108 return this->originalProxyRef(); 109 } 110 return result; 111 } 112 113 std::unique_ptr<GrFragmentProcessor> GrTextureAdjuster::createFragmentProcessor( 114 const SkMatrix& origTextureMatrix, 115 const SkRect& constraintRect, 116 FilterConstraint filterConstraint, 117 bool coordsLimitedToConstraintRect, 118 const GrSamplerState::Filter* filterOrNullForBicubic) { 119 SkMatrix textureMatrix = origTextureMatrix; 120 121 SkRect domain; 122 GrSamplerState samplerState; 123 if (filterOrNullForBicubic) { 124 samplerState.setFilterMode(*filterOrNullForBicubic); 125 } 126 SkScalar scaleAdjust[2] = { 1.0f, 1.0f }; 127 sk_sp<GrTextureProxy> proxy( 128 this->refTextureProxyForParams(samplerState, scaleAdjust)); 129 if (!proxy) { 130 return nullptr; 131 } 132 // If we made a copy then we only copied the contentArea, in which case the new texture is all 133 // content. 134 if (proxy.get() != this->originalProxy()) { 135 textureMatrix.postScale(scaleAdjust[0], scaleAdjust[1]); 136 } 137 138 DomainMode domainMode = 139 DetermineDomainMode(constraintRect, filterConstraint, coordsLimitedToConstraintRect, 140 proxy.get(), filterOrNullForBicubic, &domain); 141 if (kTightCopy_DomainMode == domainMode) { 142 // TODO: Copy the texture and adjust the texture matrix (both parts need to consider 143 // non-int constraint rect) 144 // For now: treat as bilerp and ignore what goes on above level 0. 145 146 // We only expect MIP maps to require a tight copy. 147 SkASSERT(filterOrNullForBicubic && 148 GrSamplerState::Filter::kMipMap == *filterOrNullForBicubic); 149 static const GrSamplerState::Filter kBilerp = GrSamplerState::Filter::kBilerp; 150 domainMode = 151 DetermineDomainMode(constraintRect, filterConstraint, coordsLimitedToConstraintRect, 152 proxy.get(), &kBilerp, &domain); 153 SkASSERT(kTightCopy_DomainMode != domainMode); 154 } 155 SkASSERT(kNoDomain_DomainMode == domainMode || 156 (domain.fLeft <= domain.fRight && domain.fTop <= domain.fBottom)); 157 return CreateFragmentProcessorForDomainAndFilter(std::move(proxy), textureMatrix, domainMode, 158 domain, filterOrNullForBicubic); 159 } 160