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
GrTextureAdjuster(GrContext * context,sk_sp<GrTextureProxy> original,SkAlphaType alphaType,uint32_t uniqueID,SkColorSpace * cs)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
makeCopyKey(const CopyParams & params,GrUniqueKey * copyKey)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
didCacheCopy(const GrUniqueKey & copyKey,uint32_t contextUniqueID)34 void GrTextureAdjuster::didCacheCopy(const GrUniqueKey& copyKey, uint32_t contextUniqueID) {
35 // We don't currently have a mechanism for notifications on Images!
36 }
37
refTextureProxyCopy(const CopyParams & copyParams,bool willBeMipped)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
onRefTextureProxyForParams(const GrSamplerState & params,bool willBeMipped,SkScalar scaleAdjust[2])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
createFragmentProcessor(const SkMatrix & origTextureMatrix,const SkRect & constraintRect,FilterConstraint filterConstraint,bool coordsLimitedToConstraintRect,const GrSamplerState::Filter * filterOrNullForBicubic)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