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