1 /*
2  * Copyright 2015 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 "GrTextureParamsAdjuster.h"
9 
10 #include "GrCaps.h"
11 #include "GrColorSpaceXform.h"
12 #include "GrContext.h"
13 #include "GrDrawContext.h"
14 #include "GrGpu.h"
15 #include "GrGpuResourcePriv.h"
16 #include "GrResourceKey.h"
17 #include "GrTexture.h"
18 #include "GrTextureParams.h"
19 #include "GrTextureProvider.h"
20 #include "SkCanvas.h"
21 #include "SkGr.h"
22 #include "SkGrPriv.h"
23 #include "effects/GrBicubicEffect.h"
24 #include "effects/GrSimpleTextureEffect.h"
25 #include "effects/GrTextureDomain.h"
26 
27 typedef GrTextureProducer::CopyParams CopyParams;
28 
29 //////////////////////////////////////////////////////////////////////////////
30 
copy_on_gpu(GrTexture * inputTexture,const SkIRect * subset,const CopyParams & copyParams)31 static GrTexture* copy_on_gpu(GrTexture* inputTexture, const SkIRect* subset,
32                               const CopyParams& copyParams) {
33     SkASSERT(!subset || !subset->isEmpty());
34     GrContext* context = inputTexture->getContext();
35     SkASSERT(context);
36 
37     GrPixelConfig config = GrMakePixelConfigUncompressed(inputTexture->config());
38 
39     sk_sp<GrDrawContext> copyDC = context->makeDrawContextWithFallback(SkBackingFit::kExact,
40                                                                        copyParams.fWidth,
41                                                                        copyParams.fHeight,
42                                                                        config, nullptr);
43     if (!copyDC) {
44         return nullptr;
45     }
46 
47     GrPaint paint;
48     paint.setGammaCorrect(true);
49 
50     SkScalar sx SK_INIT_TO_AVOID_WARNING;
51     SkScalar sy SK_INIT_TO_AVOID_WARNING;
52     if (subset) {
53         sx = 1.f / inputTexture->width();
54         sy = 1.f / inputTexture->height();
55     }
56 
57     if (copyParams.fFilter != GrTextureParams::kNone_FilterMode && subset &&
58         (subset->width() != copyParams.fWidth || subset->height() != copyParams.fHeight)) {
59         SkRect domain;
60         domain.fLeft = (subset->fLeft + 0.5f) * sx;
61         domain.fTop = (subset->fTop + 0.5f)* sy;
62         domain.fRight = (subset->fRight - 0.5f) * sx;
63         domain.fBottom = (subset->fBottom - 0.5f) * sy;
64         // This would cause us to read values from outside the subset. Surely, the caller knows
65         // better!
66         SkASSERT(copyParams.fFilter != GrTextureParams::kMipMap_FilterMode);
67         paint.addColorFragmentProcessor(
68             GrTextureDomainEffect::Make(inputTexture, nullptr, SkMatrix::I(), domain,
69                                         GrTextureDomain::kClamp_Mode,
70                                         copyParams.fFilter));
71     } else {
72         GrTextureParams params(SkShader::kClamp_TileMode, copyParams.fFilter);
73         paint.addColorTextureProcessor(inputTexture, nullptr, SkMatrix::I(), params);
74     }
75     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
76 
77     SkRect localRect;
78     if (subset) {
79         localRect = SkRect::Make(*subset);
80         localRect.fLeft *= sx;
81         localRect.fTop *= sy;
82         localRect.fRight *= sx;
83         localRect.fBottom *= sy;
84     } else {
85         localRect = SkRect::MakeWH(1.f, 1.f);
86     }
87 
88     SkRect dstRect = SkRect::MakeIWH(copyParams.fWidth, copyParams.fHeight);
89     copyDC->fillRectToRect(GrNoClip(), paint, SkMatrix::I(), dstRect, localRect);
90     return copyDC->asTexture().release();
91 }
92 
GrTextureAdjuster(GrTexture * original,SkAlphaType alphaType,const SkIRect & contentArea,uint32_t uniqueID,SkColorSpace * cs)93 GrTextureAdjuster::GrTextureAdjuster(GrTexture* original, SkAlphaType alphaType,
94                                      const SkIRect& contentArea, uint32_t uniqueID,
95                                      SkColorSpace* cs)
96     : INHERITED(contentArea.width(), contentArea.height(),
97                 GrPixelConfigIsAlphaOnly(original->config()))
98     , fOriginal(original)
99     , fAlphaType(alphaType)
100     , fColorSpace(cs)
101     , fUniqueID(uniqueID)
102 {
103     SkASSERT(SkIRect::MakeWH(original->width(), original->height()).contains(contentArea));
104     if (contentArea.fLeft > 0 || contentArea.fTop > 0 ||
105         contentArea.fRight < original->width() || contentArea.fBottom < original->height()) {
106         fContentArea.set(contentArea);
107     }
108 }
109 
makeCopyKey(const CopyParams & params,GrUniqueKey * copyKey)110 void GrTextureAdjuster::makeCopyKey(const CopyParams& params, GrUniqueKey* copyKey) {
111     GrUniqueKey baseKey;
112     GrMakeKeyFromImageID(&baseKey, fUniqueID, SkIRect::MakeWH(this->width(), this->height()));
113     MakeCopyKeyFromOrigKey(baseKey, params, copyKey);
114 }
115 
didCacheCopy(const GrUniqueKey & copyKey)116 void GrTextureAdjuster::didCacheCopy(const GrUniqueKey& copyKey) {
117     // We don't currently have a mechanism for notifications on Images!
118 }
119 
getColorSpace()120 SkColorSpace* GrTextureAdjuster::getColorSpace() {
121     return fColorSpace;
122 }
123 
refCopy(const CopyParams & copyParams)124 GrTexture* GrTextureAdjuster::refCopy(const CopyParams& copyParams) {
125     GrTexture* texture = this->originalTexture();
126     GrContext* context = texture->getContext();
127     const SkIRect* contentArea = this->contentAreaOrNull();
128     GrUniqueKey key;
129     this->makeCopyKey(copyParams, &key);
130     if (key.isValid()) {
131         GrTexture* cachedCopy = context->textureProvider()->findAndRefTextureByUniqueKey(key);
132         if (cachedCopy) {
133             return cachedCopy;
134         }
135     }
136     GrTexture* copy = copy_on_gpu(texture, contentArea, copyParams);
137     if (copy) {
138         if (key.isValid()) {
139             copy->resourcePriv().setUniqueKey(key);
140             this->didCacheCopy(key);
141         }
142     }
143     return copy;
144 }
145 
refTextureSafeForParams(const GrTextureParams & params,SkSourceGammaTreatment gammaTreatment,SkIPoint * outOffset)146 GrTexture* GrTextureAdjuster::refTextureSafeForParams(const GrTextureParams& params,
147                                                       SkSourceGammaTreatment gammaTreatment,
148                                                       SkIPoint* outOffset) {
149     GrTexture* texture = this->originalTexture();
150     GrContext* context = texture->getContext();
151     CopyParams copyParams;
152     const SkIRect* contentArea = this->contentAreaOrNull();
153 
154     if (!context) {
155         // The texture was abandoned.
156         return nullptr;
157     }
158 
159     if (contentArea && GrTextureParams::kMipMap_FilterMode == params.filterMode()) {
160         // If we generate a MIP chain for texture it will read pixel values from outside the content
161         // area.
162         copyParams.fWidth = contentArea->width();
163         copyParams.fHeight = contentArea->height();
164         copyParams.fFilter = GrTextureParams::kBilerp_FilterMode;
165     } else if (!context->getGpu()->makeCopyForTextureParams(texture, params, &copyParams)) {
166         if (outOffset) {
167             if (contentArea) {
168                 outOffset->set(contentArea->fLeft, contentArea->fRight);
169             } else {
170                 outOffset->set(0, 0);
171             }
172         }
173         return SkRef(texture);
174     }
175 
176     GrTexture* copy = this->refCopy(copyParams);
177     if (copy && outOffset) {
178         outOffset->set(0, 0);
179     }
180     return copy;
181 }
182 
183 enum DomainMode {
184     kNoDomain_DomainMode,
185     kDomain_DomainMode,
186     kTightCopy_DomainMode
187 };
188 
189 /** Determines whether a texture domain is necessary and if so what domain to use. There are two
190  *  rectangles to consider:
191  *  - The first is the content area specified by the texture adjuster. We can *never* allow
192  *    filtering to cause bleed of pixels outside this rectangle.
193  *  - The second rectangle is the constraint rectangle, which is known to be contained by the
194  *    content area. The filterConstraint specifies whether we are allowed to bleed across this
195  *    rect.
196  *
197  *  We want to avoid using a domain if possible. We consider the above rectangles, the filter type,
198  *  and whether the coords generated by the draw would all fall within the constraint rect. If the
199  *  latter is true we only need to consider whether the filter would extend beyond the rects.
200  */
determine_domain_mode(const SkRect & constraintRect,GrTextureAdjuster::FilterConstraint filterConstraint,bool coordsLimitedToConstraintRect,int texW,int texH,const SkIRect * textureContentArea,const GrTextureParams::FilterMode * filterModeOrNullForBicubic,SkRect * domainRect)201 static DomainMode determine_domain_mode(
202                                     const SkRect& constraintRect,
203                                     GrTextureAdjuster::FilterConstraint filterConstraint,
204                                     bool coordsLimitedToConstraintRect,
205                                     int texW, int texH,
206                                     const SkIRect* textureContentArea,
207                                     const GrTextureParams::FilterMode* filterModeOrNullForBicubic,
208                                     SkRect* domainRect) {
209 
210     SkASSERT(SkRect::MakeIWH(texW, texH).contains(constraintRect));
211     // We only expect a content area rect if there is some non-content area.
212     SkASSERT(!textureContentArea ||
213              (!textureContentArea->contains(SkIRect::MakeWH(texW, texH)) &&
214               SkRect::Make(*textureContentArea).contains(constraintRect)));
215 
216     SkRect textureBounds = SkRect::MakeIWH(texW, texH);
217     // If the src rectangle contains the whole texture then no need for a domain.
218     if (constraintRect.contains(textureBounds)) {
219         return kNoDomain_DomainMode;
220     }
221 
222     bool restrictFilterToRect = (filterConstraint == GrTextureProducer::kYes_FilterConstraint);
223 
224     // If we can filter outside the constraint rect, and there is no non-content area of the
225     // texture, and we aren't going to generate sample coords outside the constraint rect then we
226     // don't need a domain.
227     if (!restrictFilterToRect && !textureContentArea && coordsLimitedToConstraintRect) {
228         return kNoDomain_DomainMode;
229     }
230 
231     // Get the domain inset based on sampling mode (or bail if mipped)
232     SkScalar filterHalfWidth = 0.f;
233     if (filterModeOrNullForBicubic) {
234         switch (*filterModeOrNullForBicubic) {
235             case GrTextureParams::kNone_FilterMode:
236                 if (coordsLimitedToConstraintRect) {
237                     return kNoDomain_DomainMode;
238                 } else {
239                     filterHalfWidth = 0.f;
240                 }
241                 break;
242             case GrTextureParams::kBilerp_FilterMode:
243                 filterHalfWidth = .5f;
244                 break;
245             case GrTextureParams::kMipMap_FilterMode:
246                 if (restrictFilterToRect || textureContentArea) {
247                     // No domain can save us here.
248                     return kTightCopy_DomainMode;
249                 }
250                 return kNoDomain_DomainMode;
251         }
252     } else {
253         // bicubic does nearest filtering internally.
254         filterHalfWidth = 1.5f;
255     }
256 
257     // Both bilerp and bicubic use bilinear filtering and so need to be clamped to the center
258     // of the edge texel. Pinning to the texel center has no impact on nearest mode and MIP-maps
259 
260     static const SkScalar kDomainInset = 0.5f;
261     // Figure out the limits of pixels we're allowed to sample from.
262     // Unless we know the amount of outset and the texture matrix we have to conservatively enforce
263     // the domain.
264     if (restrictFilterToRect) {
265         domainRect->fLeft = constraintRect.fLeft + kDomainInset;
266         domainRect->fTop = constraintRect.fTop + kDomainInset;
267         domainRect->fRight = constraintRect.fRight - kDomainInset;
268         domainRect->fBottom = constraintRect.fBottom - kDomainInset;
269     } else if (textureContentArea) {
270         // If we got here then: there is a textureContentArea, the coords are limited to the
271         // constraint rect, and we're allowed to filter across the constraint rect boundary. So
272         // we check whether the filter would reach across the edge of the content area.
273         // We will only set the sides that are required.
274 
275         domainRect->setLargest();
276         if (coordsLimitedToConstraintRect) {
277             // We may be able to use the fact that the texture coords are limited to the constraint
278             // rect in order to avoid having to add a domain.
279             bool needContentAreaConstraint = false;
280             if (textureContentArea->fLeft > 0 &&
281                 textureContentArea->fLeft + filterHalfWidth > constraintRect.fLeft) {
282                 domainRect->fLeft = textureContentArea->fLeft + kDomainInset;
283                 needContentAreaConstraint = true;
284             }
285             if (textureContentArea->fTop > 0 &&
286                 textureContentArea->fTop + filterHalfWidth > constraintRect.fTop) {
287                 domainRect->fTop = textureContentArea->fTop + kDomainInset;
288                 needContentAreaConstraint = true;
289             }
290             if (textureContentArea->fRight < texW &&
291                 textureContentArea->fRight - filterHalfWidth < constraintRect.fRight) {
292                 domainRect->fRight = textureContentArea->fRight - kDomainInset;
293                 needContentAreaConstraint = true;
294             }
295             if (textureContentArea->fBottom < texH &&
296                 textureContentArea->fBottom - filterHalfWidth < constraintRect.fBottom) {
297                 domainRect->fBottom = textureContentArea->fBottom - kDomainInset;
298                 needContentAreaConstraint = true;
299             }
300             if (!needContentAreaConstraint) {
301                 return kNoDomain_DomainMode;
302             }
303         } else {
304             // Our sample coords for the texture are allowed to be outside the constraintRect so we
305             // don't consider it when computing the domain.
306             if (textureContentArea->fLeft != 0) {
307                 domainRect->fLeft = textureContentArea->fLeft + kDomainInset;
308             }
309             if (textureContentArea->fTop != 0) {
310                 domainRect->fTop = textureContentArea->fTop + kDomainInset;
311             }
312             if (textureContentArea->fRight != texW) {
313                 domainRect->fRight = textureContentArea->fRight - kDomainInset;
314             }
315             if (textureContentArea->fBottom != texH) {
316                 domainRect->fBottom = textureContentArea->fBottom - kDomainInset;
317             }
318         }
319     } else {
320         return kNoDomain_DomainMode;
321     }
322 
323     if (domainRect->fLeft > domainRect->fRight) {
324         domainRect->fLeft = domainRect->fRight = SkScalarAve(domainRect->fLeft, domainRect->fRight);
325     }
326     if (domainRect->fTop > domainRect->fBottom) {
327         domainRect->fTop = domainRect->fBottom = SkScalarAve(domainRect->fTop, domainRect->fBottom);
328     }
329     domainRect->fLeft /= texW;
330     domainRect->fTop /= texH;
331     domainRect->fRight /= texW;
332     domainRect->fBottom /= texH;
333     return kDomain_DomainMode;
334 }
335 
create_fp_for_domain_and_filter(GrTexture * texture,sk_sp<GrColorSpaceXform> colorSpaceXform,const SkMatrix & textureMatrix,DomainMode domainMode,const SkRect & domain,const GrTextureParams::FilterMode * filterOrNullForBicubic)336 static sk_sp<GrFragmentProcessor> create_fp_for_domain_and_filter(
337                                         GrTexture* texture,
338                                         sk_sp<GrColorSpaceXform> colorSpaceXform,
339                                         const SkMatrix& textureMatrix,
340                                         DomainMode domainMode,
341                                         const SkRect& domain,
342                                         const GrTextureParams::FilterMode* filterOrNullForBicubic) {
343     SkASSERT(kTightCopy_DomainMode != domainMode);
344     if (filterOrNullForBicubic) {
345         if (kDomain_DomainMode == domainMode) {
346             return GrTextureDomainEffect::Make(texture, std::move(colorSpaceXform), textureMatrix,
347                                                domain, GrTextureDomain::kClamp_Mode,
348                                                *filterOrNullForBicubic);
349         } else {
350             GrTextureParams params(SkShader::kClamp_TileMode, *filterOrNullForBicubic);
351             return GrSimpleTextureEffect::Make(texture, std::move(colorSpaceXform), textureMatrix,
352                                                params);
353         }
354     } else {
355         if (kDomain_DomainMode == domainMode) {
356             return GrBicubicEffect::Make(texture, std::move(colorSpaceXform), textureMatrix,
357                                          domain);
358         } else {
359             static const SkShader::TileMode kClampClamp[] =
360                 { SkShader::kClamp_TileMode, SkShader::kClamp_TileMode };
361             return GrBicubicEffect::Make(texture, std::move(colorSpaceXform), textureMatrix,
362                                          kClampClamp);
363         }
364     }
365 }
366 
createFragmentProcessor(const SkMatrix & origTextureMatrix,const SkRect & origConstraintRect,FilterConstraint filterConstraint,bool coordsLimitedToConstraintRect,const GrTextureParams::FilterMode * filterOrNullForBicubic,SkColorSpace * dstColorSpace,SkSourceGammaTreatment gammaTreatment)367 sk_sp<GrFragmentProcessor> GrTextureAdjuster::createFragmentProcessor(
368                                         const SkMatrix& origTextureMatrix,
369                                         const SkRect& origConstraintRect,
370                                         FilterConstraint filterConstraint,
371                                         bool coordsLimitedToConstraintRect,
372                                         const GrTextureParams::FilterMode* filterOrNullForBicubic,
373                                         SkColorSpace* dstColorSpace,
374                                         SkSourceGammaTreatment gammaTreatment) {
375 
376     SkMatrix textureMatrix = origTextureMatrix;
377     const SkIRect* contentArea = this->contentAreaOrNull();
378     // Convert the constraintRect to be relative to the texture rather than the content area so
379     // that both rects are in the same coordinate system.
380     SkTCopyOnFirstWrite<SkRect> constraintRect(origConstraintRect);
381     if (contentArea) {
382         SkScalar l = SkIntToScalar(contentArea->fLeft);
383         SkScalar t = SkIntToScalar(contentArea->fTop);
384         constraintRect.writable()->offset(l, t);
385         textureMatrix.postTranslate(l, t);
386     }
387 
388     SkRect domain;
389     GrTextureParams params;
390     if (filterOrNullForBicubic) {
391         params.setFilterMode(*filterOrNullForBicubic);
392     }
393     SkAutoTUnref<GrTexture> texture(this->refTextureSafeForParams(params, gammaTreatment, nullptr));
394     if (!texture) {
395         return nullptr;
396     }
397     // If we made a copy then we only copied the contentArea, in which case the new texture is all
398     // content.
399     if (texture != this->originalTexture()) {
400         contentArea = nullptr;
401     }
402 
403     DomainMode domainMode =
404         determine_domain_mode(*constraintRect, filterConstraint, coordsLimitedToConstraintRect,
405                               texture->width(), texture->height(),
406                               contentArea, filterOrNullForBicubic,
407                               &domain);
408     if (kTightCopy_DomainMode == domainMode) {
409         // TODO: Copy the texture and adjust the texture matrix (both parts need to consider
410         // non-int constraint rect)
411         // For now: treat as bilerp and ignore what goes on above level 0.
412 
413         // We only expect MIP maps to require a tight copy.
414         SkASSERT(filterOrNullForBicubic &&
415                  GrTextureParams::kMipMap_FilterMode == *filterOrNullForBicubic);
416         static const GrTextureParams::FilterMode kBilerp = GrTextureParams::kBilerp_FilterMode;
417         domainMode =
418             determine_domain_mode(*constraintRect, filterConstraint, coordsLimitedToConstraintRect,
419                                   texture->width(), texture->height(),
420                                   contentArea, &kBilerp, &domain);
421         SkASSERT(kTightCopy_DomainMode != domainMode);
422     }
423     SkASSERT(kNoDomain_DomainMode == domainMode ||
424              (domain.fLeft <= domain.fRight && domain.fTop <= domain.fBottom));
425     textureMatrix.postIDiv(texture->width(), texture->height());
426     sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(this->getColorSpace(),
427                                                                        dstColorSpace);
428     return create_fp_for_domain_and_filter(texture, std::move(colorSpaceXform), textureMatrix,
429                                            domainMode, domain, filterOrNullForBicubic);
430 }
431 
432 //////////////////////////////////////////////////////////////////////////////
433 
refTextureForParams(const GrTextureParams & params,SkSourceGammaTreatment gammaTreatment)434 GrTexture* GrTextureMaker::refTextureForParams(const GrTextureParams& params,
435                                                SkSourceGammaTreatment gammaTreatment) {
436     CopyParams copyParams;
437     bool willBeMipped = params.filterMode() == GrTextureParams::kMipMap_FilterMode;
438 
439     if (!fContext->caps()->mipMapSupport()) {
440         willBeMipped = false;
441     }
442 
443     if (!fContext->getGpu()->makeCopyForTextureParams(this->width(), this->height(), params,
444                                                       &copyParams)) {
445         return this->refOriginalTexture(willBeMipped, gammaTreatment);
446     }
447     GrUniqueKey copyKey;
448     this->makeCopyKey(copyParams, &copyKey);
449     if (copyKey.isValid()) {
450         GrTexture* result = fContext->textureProvider()->findAndRefTextureByUniqueKey(copyKey);
451         if (result) {
452             return result;
453         }
454     }
455 
456     GrTexture* result = this->generateTextureForParams(copyParams, willBeMipped, gammaTreatment);
457     if (!result) {
458         return nullptr;
459     }
460 
461     if (copyKey.isValid()) {
462         fContext->textureProvider()->assignUniqueKeyToTexture(copyKey, result);
463         this->didCacheCopy(copyKey);
464     }
465     return result;
466 }
467 
createFragmentProcessor(const SkMatrix & textureMatrix,const SkRect & constraintRect,FilterConstraint filterConstraint,bool coordsLimitedToConstraintRect,const GrTextureParams::FilterMode * filterOrNullForBicubic,SkColorSpace * dstColorSpace,SkSourceGammaTreatment gammaTreatment)468 sk_sp<GrFragmentProcessor> GrTextureMaker::createFragmentProcessor(
469                                         const SkMatrix& textureMatrix,
470                                         const SkRect& constraintRect,
471                                         FilterConstraint filterConstraint,
472                                         bool coordsLimitedToConstraintRect,
473                                         const GrTextureParams::FilterMode* filterOrNullForBicubic,
474                                         SkColorSpace* dstColorSpace,
475                                         SkSourceGammaTreatment gammaTreatment) {
476 
477     const GrTextureParams::FilterMode* fmForDetermineDomain = filterOrNullForBicubic;
478     if (filterOrNullForBicubic && GrTextureParams::kMipMap_FilterMode == *filterOrNullForBicubic &&
479         kYes_FilterConstraint == filterConstraint) {
480         // TODo: Here we should force a copy restricted to the constraintRect since MIP maps will
481         // read outside the constraint rect. However, as in the adjuster case, we aren't currently
482         // doing that.
483         // We instead we compute the domain as though were bilerping which is only correct if we
484         // only sample level 0.
485         static const GrTextureParams::FilterMode kBilerp = GrTextureParams::kBilerp_FilterMode;
486         fmForDetermineDomain = &kBilerp;
487     }
488 
489     GrTextureParams params;
490     if (filterOrNullForBicubic) {
491         params.reset(SkShader::kClamp_TileMode, *filterOrNullForBicubic);
492     } else {
493         // Bicubic doesn't use filtering for it's texture accesses.
494         params.reset(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode);
495     }
496     SkAutoTUnref<GrTexture> texture(this->refTextureForParams(params, gammaTreatment));
497     if (!texture) {
498         return nullptr;
499     }
500     SkRect domain;
501     DomainMode domainMode =
502         determine_domain_mode(constraintRect, filterConstraint, coordsLimitedToConstraintRect,
503                               texture->width(), texture->height(), nullptr, fmForDetermineDomain,
504                               &domain);
505     SkASSERT(kTightCopy_DomainMode != domainMode);
506     SkMatrix normalizedTextureMatrix = textureMatrix;
507     normalizedTextureMatrix.postIDiv(texture->width(), texture->height());
508     sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(this->getColorSpace(),
509                                                                        dstColorSpace);
510     return create_fp_for_domain_and_filter(texture, std::move(colorSpaceXform),
511                                            normalizedTextureMatrix, domainMode, domain,
512                                            filterOrNullForBicubic);
513 }
514 
generateTextureForParams(const CopyParams & copyParams,bool willBeMipped,SkSourceGammaTreatment gammaTreatment)515 GrTexture* GrTextureMaker::generateTextureForParams(const CopyParams& copyParams, bool willBeMipped,
516                                                     SkSourceGammaTreatment gammaTreatment) {
517     SkAutoTUnref<GrTexture> original(this->refOriginalTexture(willBeMipped, gammaTreatment));
518     if (!original) {
519         return nullptr;
520     }
521     return copy_on_gpu(original, nullptr, copyParams);
522 }
523