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
10 #include "GrContext.h"
11 #include "GrGpu.h"
12 #include "GrResourceProvider.h"
13 #include "SkGr.h"
14
GrTextureAdjuster(GrContext * context,sk_sp<GrTextureProxy> original,SkAlphaType alphaType,const SkIRect & contentArea,uint32_t uniqueID,SkColorSpace * cs)15 GrTextureAdjuster::GrTextureAdjuster(GrContext* context, sk_sp<GrTextureProxy> original,
16 SkAlphaType alphaType,
17 const SkIRect& contentArea, uint32_t uniqueID,
18 SkColorSpace* cs)
19 : INHERITED(contentArea.width(), contentArea.height(),
20 GrPixelConfigIsAlphaOnly(original->config()))
21 , fContext(context)
22 , fOriginal(std::move(original))
23 , fAlphaType(alphaType)
24 , fColorSpace(cs)
25 , fUniqueID(uniqueID) {
26 SkASSERT(SkIRect::MakeWH(fOriginal->width(), fOriginal->height()).contains(contentArea));
27 if (contentArea.fLeft > 0 || contentArea.fTop > 0 ||
28 contentArea.fRight < fOriginal->width() || contentArea.fBottom < fOriginal->height()) {
29 fContentArea.set(contentArea);
30 }
31 }
32
makeCopyKey(const CopyParams & params,GrUniqueKey * copyKey,SkColorSpace * dstColorSpace)33 void GrTextureAdjuster::makeCopyKey(const CopyParams& params, GrUniqueKey* copyKey,
34 SkColorSpace* dstColorSpace) {
35 // Destination color space is irrelevant - we already have a texture so we're just sub-setting
36 GrUniqueKey baseKey;
37 GrMakeKeyFromImageID(&baseKey, fUniqueID, SkIRect::MakeWH(this->width(), this->height()));
38 MakeCopyKeyFromOrigKey(baseKey, params, copyKey);
39 }
40
didCacheCopy(const GrUniqueKey & copyKey)41 void GrTextureAdjuster::didCacheCopy(const GrUniqueKey& copyKey) {
42 // We don't currently have a mechanism for notifications on Images!
43 }
44
refTextureProxyCopy(const CopyParams & copyParams)45 sk_sp<GrTextureProxy> GrTextureAdjuster::refTextureProxyCopy(const CopyParams& copyParams) {
46 GrUniqueKey key;
47 this->makeCopyKey(copyParams, &key, nullptr);
48 if (key.isValid()) {
49 sk_sp<GrTextureProxy> cachedCopy = fContext->resourceProvider()->findProxyByUniqueKey(key);
50 if (cachedCopy) {
51 return cachedCopy;
52 }
53 }
54
55 sk_sp<GrTextureProxy> proxy = this->originalProxyRef();
56 const SkIRect* contentArea = this->contentAreaOrNull();
57
58 sk_sp<GrTextureProxy> copy = CopyOnGpu(fContext, std::move(proxy), contentArea, copyParams);
59 if (copy) {
60 if (key.isValid()) {
61 fContext->resourceProvider()->assignUniqueKeyToProxy(key, copy.get());
62 this->didCacheCopy(key);
63 }
64 }
65 return copy;
66 }
67
refTextureProxySafeForParams(const GrSamplerParams & params,SkIPoint * outOffset,SkScalar scaleAdjust[2])68 sk_sp<GrTextureProxy> GrTextureAdjuster::refTextureProxySafeForParams(
69 const GrSamplerParams& params,
70 SkIPoint* outOffset,
71 SkScalar scaleAdjust[2]) {
72 sk_sp<GrTextureProxy> proxy = this->originalProxyRef();
73 CopyParams copyParams;
74 const SkIRect* contentArea = this->contentAreaOrNull();
75
76 if (!fContext) {
77 // The texture was abandoned.
78 return nullptr;
79 }
80
81 if (contentArea && GrSamplerParams::kMipMap_FilterMode == params.filterMode()) {
82 // If we generate a MIP chain for texture it will read pixel values from outside the content
83 // area.
84 copyParams.fWidth = contentArea->width();
85 copyParams.fHeight = contentArea->height();
86 copyParams.fFilter = GrSamplerParams::kBilerp_FilterMode;
87 } else if (!fContext->getGpu()->isACopyNeededForTextureParams(proxy.get(), params, ©Params,
88 scaleAdjust)) {
89 if (outOffset) {
90 if (contentArea) {
91 outOffset->set(contentArea->fLeft, contentArea->fRight);
92 } else {
93 outOffset->set(0, 0);
94 }
95 }
96 return proxy;
97 }
98
99 sk_sp<GrTextureProxy> copy = this->refTextureProxyCopy(copyParams);
100 if (copy && outOffset) {
101 outOffset->set(0, 0);
102 }
103 return copy;
104 }
105
createFragmentProcessor(const SkMatrix & origTextureMatrix,const SkRect & origConstraintRect,FilterConstraint filterConstraint,bool coordsLimitedToConstraintRect,const GrSamplerParams::FilterMode * filterOrNullForBicubic,SkColorSpace * dstColorSpace)106 sk_sp<GrFragmentProcessor> GrTextureAdjuster::createFragmentProcessor(
107 const SkMatrix& origTextureMatrix,
108 const SkRect& origConstraintRect,
109 FilterConstraint filterConstraint,
110 bool coordsLimitedToConstraintRect,
111 const GrSamplerParams::FilterMode* filterOrNullForBicubic,
112 SkColorSpace* dstColorSpace) {
113
114 SkMatrix textureMatrix = origTextureMatrix;
115 const SkIRect* contentArea = this->contentAreaOrNull();
116 // Convert the constraintRect to be relative to the texture rather than the content area so
117 // that both rects are in the same coordinate system.
118 SkTCopyOnFirstWrite<SkRect> constraintRect(origConstraintRect);
119 if (contentArea) {
120 SkScalar l = SkIntToScalar(contentArea->fLeft);
121 SkScalar t = SkIntToScalar(contentArea->fTop);
122 constraintRect.writable()->offset(l, t);
123 textureMatrix.postTranslate(l, t);
124 }
125
126 SkRect domain;
127 GrSamplerParams params;
128 if (filterOrNullForBicubic) {
129 params.setFilterMode(*filterOrNullForBicubic);
130 }
131 SkScalar scaleAdjust[2] = { 1.0f, 1.0f };
132 sk_sp<GrTextureProxy> proxy(this->refTextureProxySafeForParams(params, nullptr, scaleAdjust));
133 if (!proxy) {
134 return nullptr;
135 }
136 // If we made a copy then we only copied the contentArea, in which case the new texture is all
137 // content.
138 if (proxy.get() != this->originalProxy()) {
139 contentArea = nullptr;
140 textureMatrix.postScale(scaleAdjust[0], scaleAdjust[1]);
141 }
142
143 DomainMode domainMode =
144 DetermineDomainMode(*constraintRect, filterConstraint, coordsLimitedToConstraintRect,
145 proxy.get(),
146 contentArea, filterOrNullForBicubic,
147 &domain);
148 if (kTightCopy_DomainMode == domainMode) {
149 // TODO: Copy the texture and adjust the texture matrix (both parts need to consider
150 // non-int constraint rect)
151 // For now: treat as bilerp and ignore what goes on above level 0.
152
153 // We only expect MIP maps to require a tight copy.
154 SkASSERT(filterOrNullForBicubic &&
155 GrSamplerParams::kMipMap_FilterMode == *filterOrNullForBicubic);
156 static const GrSamplerParams::FilterMode kBilerp = GrSamplerParams::kBilerp_FilterMode;
157 domainMode =
158 DetermineDomainMode(*constraintRect, filterConstraint, coordsLimitedToConstraintRect,
159 proxy.get(),
160 contentArea, &kBilerp, &domain);
161 SkASSERT(kTightCopy_DomainMode != domainMode);
162 }
163 SkASSERT(kNoDomain_DomainMode == domainMode ||
164 (domain.fLeft <= domain.fRight && domain.fTop <= domain.fBottom));
165 sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(fColorSpace,
166 dstColorSpace);
167 return CreateFragmentProcessorForDomainAndFilter(std::move(proxy),
168 std::move(colorSpaceXform),
169 textureMatrix, domainMode, domain,
170 filterOrNullForBicubic);
171 }
172