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 ©Params, scaleAdjust)) {
97 needsCopyForMipsOnly = GrGpu::IsACopyNeededForMips(this->context()->priv().caps(),
98 proxy.get(), params.filter(),
99 ©Params);
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