blob: b4f5e686d9163b89f6789fb97ac8cbcced1b811d [file] [log] [blame]
bsalomon045802d2015-10-20 07:58:01 -07001/*
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"
brianosman54f30c12016-07-18 10:53:52 -070011#include "GrColorSpaceXform.h"
bsalomon045802d2015-10-20 07:58:01 -070012#include "GrContext.h"
Brian Osman11052242016-10-27 14:47:55 -040013#include "GrRenderTargetContext.h"
bsalomon045802d2015-10-20 07:58:01 -070014#include "GrGpu.h"
bsalomon89fe56b2015-10-29 10:49:28 -070015#include "GrGpuResourcePriv.h"
16#include "GrResourceKey.h"
bsalomon045802d2015-10-20 07:58:01 -070017#include "GrTexture.h"
18#include "GrTextureParams.h"
19#include "GrTextureProvider.h"
20#include "SkCanvas.h"
21#include "SkGr.h"
22#include "SkGrPriv.h"
bsalomonc55271f2015-11-09 11:55:57 -080023#include "effects/GrBicubicEffect.h"
robertphillips28a838e2016-06-23 14:07:00 -070024#include "effects/GrSimpleTextureEffect.h"
bsalomon89fe56b2015-10-29 10:49:28 -070025#include "effects/GrTextureDomain.h"
bsalomon045802d2015-10-20 07:58:01 -070026
bsalomon89fe56b2015-10-29 10:49:28 -070027typedef GrTextureProducer::CopyParams CopyParams;
bsalomon045802d2015-10-20 07:58:01 -070028
bsalomon89fe56b2015-10-29 10:49:28 -070029//////////////////////////////////////////////////////////////////////////////
30
31static GrTexture* copy_on_gpu(GrTexture* inputTexture, const SkIRect* subset,
32 const CopyParams& copyParams) {
33 SkASSERT(!subset || !subset->isEmpty());
bsalomon045802d2015-10-20 07:58:01 -070034 GrContext* context = inputTexture->getContext();
35 SkASSERT(context);
bsalomon045802d2015-10-20 07:58:01 -070036
bsalomon916e02a2016-07-19 08:12:30 -070037 GrPixelConfig config = GrMakePixelConfigUncompressed(inputTexture->config());
bsalomon045802d2015-10-20 07:58:01 -070038
Brian Osman693a5402016-10-27 15:13:22 -040039 sk_sp<GrRenderTargetContext> copyRTC = context->makeRenderTargetContextWithFallback(
Brian Osman11052242016-10-27 14:47:55 -040040 SkBackingFit::kExact, copyParams.fWidth, copyParams.fHeight, config, nullptr);
Brian Osman693a5402016-10-27 15:13:22 -040041 if (!copyRTC) {
bsalomon045802d2015-10-20 07:58:01 -070042 return nullptr;
43 }
44
45 GrPaint paint;
brianosman97fc9302016-05-12 07:53:45 -070046 paint.setGammaCorrect(true);
bsalomon045802d2015-10-20 07:58:01 -070047
bsalomon916e02a2016-07-19 08:12:30 -070048 SkScalar sx SK_INIT_TO_AVOID_WARNING;
49 SkScalar sy SK_INIT_TO_AVOID_WARNING;
bsalomon89fe56b2015-10-29 10:49:28 -070050 if (subset) {
51 sx = 1.f / inputTexture->width();
52 sy = 1.f / inputTexture->height();
53 }
bsalomon045802d2015-10-20 07:58:01 -070054
bsalomon89fe56b2015-10-29 10:49:28 -070055 if (copyParams.fFilter != GrTextureParams::kNone_FilterMode && subset &&
56 (subset->width() != copyParams.fWidth || subset->height() != copyParams.fHeight)) {
57 SkRect domain;
58 domain.fLeft = (subset->fLeft + 0.5f) * sx;
59 domain.fTop = (subset->fTop + 0.5f)* sy;
60 domain.fRight = (subset->fRight - 0.5f) * sx;
61 domain.fBottom = (subset->fBottom - 0.5f) * sy;
62 // This would cause us to read values from outside the subset. Surely, the caller knows
63 // better!
64 SkASSERT(copyParams.fFilter != GrTextureParams::kMipMap_FilterMode);
65 paint.addColorFragmentProcessor(
brianosman54f30c12016-07-18 10:53:52 -070066 GrTextureDomainEffect::Make(inputTexture, nullptr, SkMatrix::I(), domain,
bungeman06ca8ec2016-06-09 08:01:03 -070067 GrTextureDomain::kClamp_Mode,
68 copyParams.fFilter));
bsalomon89fe56b2015-10-29 10:49:28 -070069 } else {
70 GrTextureParams params(SkShader::kClamp_TileMode, copyParams.fFilter);
brianosman54f30c12016-07-18 10:53:52 -070071 paint.addColorTextureProcessor(inputTexture, nullptr, SkMatrix::I(), params);
bsalomon89fe56b2015-10-29 10:49:28 -070072 }
reed374772b2016-10-05 17:33:02 -070073 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
bsalomon89fe56b2015-10-29 10:49:28 -070074
75 SkRect localRect;
76 if (subset) {
77 localRect = SkRect::Make(*subset);
78 localRect.fLeft *= sx;
79 localRect.fTop *= sy;
80 localRect.fRight *= sx;
81 localRect.fBottom *= sy;
82 } else {
83 localRect = SkRect::MakeWH(1.f, 1.f);
84 }
bsalomon045802d2015-10-20 07:58:01 -070085
bsalomon916e02a2016-07-19 08:12:30 -070086 SkRect dstRect = SkRect::MakeIWH(copyParams.fWidth, copyParams.fHeight);
Brian Osman693a5402016-10-27 15:13:22 -040087 copyRTC->fillRectToRect(GrNoClip(), paint, SkMatrix::I(), dstRect, localRect);
88 return copyRTC->asTexture().release();
bsalomon045802d2015-10-20 07:58:01 -070089}
90
brianosman5814b8a2016-08-18 06:43:03 -070091GrTextureAdjuster::GrTextureAdjuster(GrTexture* original, SkAlphaType alphaType,
92 const SkIRect& contentArea, uint32_t uniqueID,
93 SkColorSpace* cs)
reedc6874482016-08-16 06:39:39 -070094 : INHERITED(contentArea.width(), contentArea.height(),
95 GrPixelConfigIsAlphaOnly(original->config()))
96 , fOriginal(original)
brianosman5814b8a2016-08-18 06:43:03 -070097 , fAlphaType(alphaType)
reedc6874482016-08-16 06:39:39 -070098 , fColorSpace(cs)
99 , fUniqueID(uniqueID)
100{
bsalomon3aa5fce2015-11-12 09:59:44 -0800101 SkASSERT(SkIRect::MakeWH(original->width(), original->height()).contains(contentArea));
bsalomonc75be342015-10-29 12:34:31 -0700102 if (contentArea.fLeft > 0 || contentArea.fTop > 0 ||
103 contentArea.fRight < original->width() || contentArea.fBottom < original->height()) {
104 fContentArea.set(contentArea);
bsalomon89fe56b2015-10-29 10:49:28 -0700105 }
106}
107
reedc6874482016-08-16 06:39:39 -0700108void GrTextureAdjuster::makeCopyKey(const CopyParams& params, GrUniqueKey* copyKey) {
109 GrUniqueKey baseKey;
110 GrMakeKeyFromImageID(&baseKey, fUniqueID, SkIRect::MakeWH(this->width(), this->height()));
111 MakeCopyKeyFromOrigKey(baseKey, params, copyKey);
112}
113
114void GrTextureAdjuster::didCacheCopy(const GrUniqueKey& copyKey) {
115 // We don't currently have a mechanism for notifications on Images!
116}
117
118SkColorSpace* GrTextureAdjuster::getColorSpace() {
119 return fColorSpace;
120}
121
bsalomone179a912016-01-20 06:18:10 -0800122GrTexture* GrTextureAdjuster::refCopy(const CopyParams& copyParams) {
123 GrTexture* texture = this->originalTexture();
124 GrContext* context = texture->getContext();
125 const SkIRect* contentArea = this->contentAreaOrNull();
126 GrUniqueKey key;
127 this->makeCopyKey(copyParams, &key);
128 if (key.isValid()) {
129 GrTexture* cachedCopy = context->textureProvider()->findAndRefTextureByUniqueKey(key);
130 if (cachedCopy) {
131 return cachedCopy;
132 }
133 }
134 GrTexture* copy = copy_on_gpu(texture, contentArea, copyParams);
135 if (copy) {
136 if (key.isValid()) {
137 copy->resourcePriv().setUniqueKey(key);
138 this->didCacheCopy(key);
139 }
140 }
141 return copy;
142}
143
bsalomon89fe56b2015-10-29 10:49:28 -0700144GrTexture* GrTextureAdjuster::refTextureSafeForParams(const GrTextureParams& params,
brianosman982eb7f2016-06-06 13:10:58 -0700145 SkSourceGammaTreatment gammaTreatment,
bsalomon89fe56b2015-10-29 10:49:28 -0700146 SkIPoint* outOffset) {
147 GrTexture* texture = this->originalTexture();
148 GrContext* context = texture->getContext();
149 CopyParams copyParams;
bsalomonc55271f2015-11-09 11:55:57 -0800150 const SkIRect* contentArea = this->contentAreaOrNull();
bsalomon89fe56b2015-10-29 10:49:28 -0700151
bsalomon352f3452016-06-14 16:13:09 -0700152 if (!context) {
153 // The texture was abandoned.
154 return nullptr;
155 }
156
bsalomonc75be342015-10-29 12:34:31 -0700157 if (contentArea && GrTextureParams::kMipMap_FilterMode == params.filterMode()) {
158 // If we generate a MIP chain for texture it will read pixel values from outside the content
159 // area.
160 copyParams.fWidth = contentArea->width();
161 copyParams.fHeight = contentArea->height();
162 copyParams.fFilter = GrTextureParams::kBilerp_FilterMode;
bsalomone179a912016-01-20 06:18:10 -0800163 } else if (!context->getGpu()->makeCopyForTextureParams(texture, params, &copyParams)) {
bsalomon89fe56b2015-10-29 10:49:28 -0700164 if (outOffset) {
bsalomonc75be342015-10-29 12:34:31 -0700165 if (contentArea) {
166 outOffset->set(contentArea->fLeft, contentArea->fRight);
bsalomon89fe56b2015-10-29 10:49:28 -0700167 } else {
168 outOffset->set(0, 0);
169 }
170 }
171 return SkRef(texture);
172 }
bsalomone179a912016-01-20 06:18:10 -0800173
174 GrTexture* copy = this->refCopy(copyParams);
175 if (copy && outOffset) {
176 outOffset->set(0, 0);
bsalomon89fe56b2015-10-29 10:49:28 -0700177 }
bsalomone179a912016-01-20 06:18:10 -0800178 return copy;
bsalomon89fe56b2015-10-29 10:49:28 -0700179}
180
bsalomonc55271f2015-11-09 11:55:57 -0800181enum DomainMode {
182 kNoDomain_DomainMode,
183 kDomain_DomainMode,
184 kTightCopy_DomainMode
185};
186
187/** Determines whether a texture domain is necessary and if so what domain to use. There are two
188 * rectangles to consider:
189 * - The first is the content area specified by the texture adjuster. We can *never* allow
190 * filtering to cause bleed of pixels outside this rectangle.
191 * - The second rectangle is the constraint rectangle, which is known to be contained by the
192 * content area. The filterConstraint specifies whether we are allowed to bleed across this
193 * rect.
194 *
195 * We want to avoid using a domain if possible. We consider the above rectangles, the filter type,
196 * and whether the coords generated by the draw would all fall within the constraint rect. If the
197 * latter is true we only need to consider whether the filter would extend beyond the rects.
198 */
199static DomainMode determine_domain_mode(
200 const SkRect& constraintRect,
201 GrTextureAdjuster::FilterConstraint filterConstraint,
202 bool coordsLimitedToConstraintRect,
203 int texW, int texH,
204 const SkIRect* textureContentArea,
205 const GrTextureParams::FilterMode* filterModeOrNullForBicubic,
206 SkRect* domainRect) {
207
208 SkASSERT(SkRect::MakeIWH(texW, texH).contains(constraintRect));
209 // We only expect a content area rect if there is some non-content area.
210 SkASSERT(!textureContentArea ||
211 (!textureContentArea->contains(SkIRect::MakeWH(texW, texH)) &&
212 SkRect::Make(*textureContentArea).contains(constraintRect)));
213
214 SkRect textureBounds = SkRect::MakeIWH(texW, texH);
215 // If the src rectangle contains the whole texture then no need for a domain.
216 if (constraintRect.contains(textureBounds)) {
217 return kNoDomain_DomainMode;
218 }
219
bsalomonb1b01992015-11-18 10:56:08 -0800220 bool restrictFilterToRect = (filterConstraint == GrTextureProducer::kYes_FilterConstraint);
bsalomonc55271f2015-11-09 11:55:57 -0800221
222 // If we can filter outside the constraint rect, and there is no non-content area of the
223 // texture, and we aren't going to generate sample coords outside the constraint rect then we
224 // don't need a domain.
225 if (!restrictFilterToRect && !textureContentArea && coordsLimitedToConstraintRect) {
226 return kNoDomain_DomainMode;
227 }
228
229 // Get the domain inset based on sampling mode (or bail if mipped)
230 SkScalar filterHalfWidth = 0.f;
231 if (filterModeOrNullForBicubic) {
232 switch (*filterModeOrNullForBicubic) {
233 case GrTextureParams::kNone_FilterMode:
234 if (coordsLimitedToConstraintRect) {
235 return kNoDomain_DomainMode;
236 } else {
237 filterHalfWidth = 0.f;
238 }
239 break;
240 case GrTextureParams::kBilerp_FilterMode:
241 filterHalfWidth = .5f;
242 break;
243 case GrTextureParams::kMipMap_FilterMode:
bsalomonb1b01992015-11-18 10:56:08 -0800244 if (restrictFilterToRect || textureContentArea) {
245 // No domain can save us here.
246 return kTightCopy_DomainMode;
247 }
248 return kNoDomain_DomainMode;
bsalomonc55271f2015-11-09 11:55:57 -0800249 }
250 } else {
251 // bicubic does nearest filtering internally.
252 filterHalfWidth = 1.5f;
253 }
254
255 // Both bilerp and bicubic use bilinear filtering and so need to be clamped to the center
256 // of the edge texel. Pinning to the texel center has no impact on nearest mode and MIP-maps
257
258 static const SkScalar kDomainInset = 0.5f;
259 // Figure out the limits of pixels we're allowed to sample from.
260 // Unless we know the amount of outset and the texture matrix we have to conservatively enforce
261 // the domain.
262 if (restrictFilterToRect) {
263 domainRect->fLeft = constraintRect.fLeft + kDomainInset;
264 domainRect->fTop = constraintRect.fTop + kDomainInset;
265 domainRect->fRight = constraintRect.fRight - kDomainInset;
266 domainRect->fBottom = constraintRect.fBottom - kDomainInset;
267 } else if (textureContentArea) {
268 // If we got here then: there is a textureContentArea, the coords are limited to the
269 // constraint rect, and we're allowed to filter across the constraint rect boundary. So
270 // we check whether the filter would reach across the edge of the content area.
271 // We will only set the sides that are required.
272
273 domainRect->setLargest();
274 if (coordsLimitedToConstraintRect) {
275 // We may be able to use the fact that the texture coords are limited to the constraint
276 // rect in order to avoid having to add a domain.
277 bool needContentAreaConstraint = false;
278 if (textureContentArea->fLeft > 0 &&
279 textureContentArea->fLeft + filterHalfWidth > constraintRect.fLeft) {
280 domainRect->fLeft = textureContentArea->fLeft + kDomainInset;
281 needContentAreaConstraint = true;
282 }
283 if (textureContentArea->fTop > 0 &&
284 textureContentArea->fTop + filterHalfWidth > constraintRect.fTop) {
285 domainRect->fTop = textureContentArea->fTop + kDomainInset;
286 needContentAreaConstraint = true;
287 }
288 if (textureContentArea->fRight < texW &&
289 textureContentArea->fRight - filterHalfWidth < constraintRect.fRight) {
290 domainRect->fRight = textureContentArea->fRight - kDomainInset;
291 needContentAreaConstraint = true;
292 }
293 if (textureContentArea->fBottom < texH &&
294 textureContentArea->fBottom - filterHalfWidth < constraintRect.fBottom) {
295 domainRect->fBottom = textureContentArea->fBottom - kDomainInset;
296 needContentAreaConstraint = true;
297 }
298 if (!needContentAreaConstraint) {
299 return kNoDomain_DomainMode;
300 }
301 } else {
302 // Our sample coords for the texture are allowed to be outside the constraintRect so we
303 // don't consider it when computing the domain.
304 if (textureContentArea->fLeft != 0) {
305 domainRect->fLeft = textureContentArea->fLeft + kDomainInset;
306 }
307 if (textureContentArea->fTop != 0) {
308 domainRect->fTop = textureContentArea->fTop + kDomainInset;
309 }
310 if (textureContentArea->fRight != texW) {
311 domainRect->fRight = textureContentArea->fRight - kDomainInset;
312 }
313 if (textureContentArea->fBottom != texH) {
314 domainRect->fBottom = textureContentArea->fBottom - kDomainInset;
315 }
316 }
317 } else {
318 return kNoDomain_DomainMode;
319 }
320
321 if (domainRect->fLeft > domainRect->fRight) {
322 domainRect->fLeft = domainRect->fRight = SkScalarAve(domainRect->fLeft, domainRect->fRight);
323 }
324 if (domainRect->fTop > domainRect->fBottom) {
325 domainRect->fTop = domainRect->fBottom = SkScalarAve(domainRect->fTop, domainRect->fBottom);
326 }
327 domainRect->fLeft /= texW;
328 domainRect->fTop /= texH;
329 domainRect->fRight /= texW;
330 domainRect->fBottom /= texH;
331 return kDomain_DomainMode;
332}
333
bungeman06ca8ec2016-06-09 08:01:03 -0700334static sk_sp<GrFragmentProcessor> create_fp_for_domain_and_filter(
bsalomonb1b01992015-11-18 10:56:08 -0800335 GrTexture* texture,
brianosman54f30c12016-07-18 10:53:52 -0700336 sk_sp<GrColorSpaceXform> colorSpaceXform,
bsalomonb1b01992015-11-18 10:56:08 -0800337 const SkMatrix& textureMatrix,
338 DomainMode domainMode,
339 const SkRect& domain,
340 const GrTextureParams::FilterMode* filterOrNullForBicubic) {
341 SkASSERT(kTightCopy_DomainMode != domainMode);
342 if (filterOrNullForBicubic) {
343 if (kDomain_DomainMode == domainMode) {
brianosman54f30c12016-07-18 10:53:52 -0700344 return GrTextureDomainEffect::Make(texture, std::move(colorSpaceXform), textureMatrix,
345 domain, GrTextureDomain::kClamp_Mode,
bungeman06ca8ec2016-06-09 08:01:03 -0700346 *filterOrNullForBicubic);
bsalomonb1b01992015-11-18 10:56:08 -0800347 } else {
348 GrTextureParams params(SkShader::kClamp_TileMode, *filterOrNullForBicubic);
brianosman54f30c12016-07-18 10:53:52 -0700349 return GrSimpleTextureEffect::Make(texture, std::move(colorSpaceXform), textureMatrix,
350 params);
bsalomonb1b01992015-11-18 10:56:08 -0800351 }
352 } else {
353 if (kDomain_DomainMode == domainMode) {
brianosman54f30c12016-07-18 10:53:52 -0700354 return GrBicubicEffect::Make(texture, std::move(colorSpaceXform), textureMatrix,
355 domain);
bsalomonb1b01992015-11-18 10:56:08 -0800356 } else {
357 static const SkShader::TileMode kClampClamp[] =
bsalomone179a912016-01-20 06:18:10 -0800358 { SkShader::kClamp_TileMode, SkShader::kClamp_TileMode };
brianosman54f30c12016-07-18 10:53:52 -0700359 return GrBicubicEffect::Make(texture, std::move(colorSpaceXform), textureMatrix,
360 kClampClamp);
bsalomonb1b01992015-11-18 10:56:08 -0800361 }
362 }
363}
364
bungeman06ca8ec2016-06-09 08:01:03 -0700365sk_sp<GrFragmentProcessor> GrTextureAdjuster::createFragmentProcessor(
bsalomon3aa5fce2015-11-12 09:59:44 -0800366 const SkMatrix& origTextureMatrix,
367 const SkRect& origConstraintRect,
bsalomonc55271f2015-11-09 11:55:57 -0800368 FilterConstraint filterConstraint,
369 bool coordsLimitedToConstraintRect,
brianosman982eb7f2016-06-06 13:10:58 -0700370 const GrTextureParams::FilterMode* filterOrNullForBicubic,
brianosman500bb3e2016-07-22 10:33:07 -0700371 SkColorSpace* dstColorSpace,
brianosman982eb7f2016-06-06 13:10:58 -0700372 SkSourceGammaTreatment gammaTreatment) {
bsalomonc55271f2015-11-09 11:55:57 -0800373
bsalomon3aa5fce2015-11-12 09:59:44 -0800374 SkMatrix textureMatrix = origTextureMatrix;
bsalomonc55271f2015-11-09 11:55:57 -0800375 const SkIRect* contentArea = this->contentAreaOrNull();
bsalomon3aa5fce2015-11-12 09:59:44 -0800376 // Convert the constraintRect to be relative to the texture rather than the content area so
377 // that both rects are in the same coordinate system.
378 SkTCopyOnFirstWrite<SkRect> constraintRect(origConstraintRect);
379 if (contentArea) {
380 SkScalar l = SkIntToScalar(contentArea->fLeft);
381 SkScalar t = SkIntToScalar(contentArea->fTop);
382 constraintRect.writable()->offset(l, t);
383 textureMatrix.postTranslate(l, t);
384 }
bsalomonc55271f2015-11-09 11:55:57 -0800385
386 SkRect domain;
bsalomone179a912016-01-20 06:18:10 -0800387 GrTextureParams params;
388 if (filterOrNullForBicubic) {
389 params.setFilterMode(*filterOrNullForBicubic);
390 }
brianosman982eb7f2016-06-06 13:10:58 -0700391 SkAutoTUnref<GrTexture> texture(this->refTextureSafeForParams(params, gammaTreatment, nullptr));
bsalomone179a912016-01-20 06:18:10 -0800392 if (!texture) {
393 return nullptr;
394 }
395 // If we made a copy then we only copied the contentArea, in which case the new texture is all
396 // content.
397 if (texture != this->originalTexture()) {
398 contentArea = nullptr;
399 }
400
bsalomonc55271f2015-11-09 11:55:57 -0800401 DomainMode domainMode =
bsalomon3aa5fce2015-11-12 09:59:44 -0800402 determine_domain_mode(*constraintRect, filterConstraint, coordsLimitedToConstraintRect,
bsalomonc55271f2015-11-09 11:55:57 -0800403 texture->width(), texture->height(),
404 contentArea, filterOrNullForBicubic,
405 &domain);
406 if (kTightCopy_DomainMode == domainMode) {
407 // TODO: Copy the texture and adjust the texture matrix (both parts need to consider
408 // non-int constraint rect)
409 // For now: treat as bilerp and ignore what goes on above level 0.
410
411 // We only expect MIP maps to require a tight copy.
412 SkASSERT(filterOrNullForBicubic &&
413 GrTextureParams::kMipMap_FilterMode == *filterOrNullForBicubic);
414 static const GrTextureParams::FilterMode kBilerp = GrTextureParams::kBilerp_FilterMode;
415 domainMode =
bsalomon3aa5fce2015-11-12 09:59:44 -0800416 determine_domain_mode(*constraintRect, filterConstraint, coordsLimitedToConstraintRect,
bsalomonc55271f2015-11-09 11:55:57 -0800417 texture->width(), texture->height(),
418 contentArea, &kBilerp, &domain);
419 SkASSERT(kTightCopy_DomainMode != domainMode);
bsalomonc55271f2015-11-09 11:55:57 -0800420 }
421 SkASSERT(kNoDomain_DomainMode == domainMode ||
422 (domain.fLeft <= domain.fRight && domain.fTop <= domain.fBottom));
bsalomon3aa5fce2015-11-12 09:59:44 -0800423 textureMatrix.postIDiv(texture->width(), texture->height());
brianosman54f30c12016-07-18 10:53:52 -0700424 sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(this->getColorSpace(),
brianosman51924752016-09-12 08:50:19 -0700425 dstColorSpace);
brianosman54f30c12016-07-18 10:53:52 -0700426 return create_fp_for_domain_and_filter(texture, std::move(colorSpaceXform), textureMatrix,
427 domainMode, domain, filterOrNullForBicubic);
bsalomonc55271f2015-11-09 11:55:57 -0800428}
429
bsalomon89fe56b2015-10-29 10:49:28 -0700430//////////////////////////////////////////////////////////////////////////////
431
brianosman982eb7f2016-06-06 13:10:58 -0700432GrTexture* GrTextureMaker::refTextureForParams(const GrTextureParams& params,
433 SkSourceGammaTreatment gammaTreatment) {
bsalomon045802d2015-10-20 07:58:01 -0700434 CopyParams copyParams;
cblume55f2d2d2016-02-26 13:20:48 -0800435 bool willBeMipped = params.filterMode() == GrTextureParams::kMipMap_FilterMode;
436
437 if (!fContext->caps()->mipMapSupport()) {
438 willBeMipped = false;
439 }
440
bsalomonb1b01992015-11-18 10:56:08 -0800441 if (!fContext->getGpu()->makeCopyForTextureParams(this->width(), this->height(), params,
442 &copyParams)) {
brianosman982eb7f2016-06-06 13:10:58 -0700443 return this->refOriginalTexture(willBeMipped, gammaTreatment);
bsalomon045802d2015-10-20 07:58:01 -0700444 }
445 GrUniqueKey copyKey;
446 this->makeCopyKey(copyParams, &copyKey);
447 if (copyKey.isValid()) {
bsalomonb1b01992015-11-18 10:56:08 -0800448 GrTexture* result = fContext->textureProvider()->findAndRefTextureByUniqueKey(copyKey);
bsalomon045802d2015-10-20 07:58:01 -0700449 if (result) {
450 return result;
451 }
452 }
453
brianosman982eb7f2016-06-06 13:10:58 -0700454 GrTexture* result = this->generateTextureForParams(copyParams, willBeMipped, gammaTreatment);
bsalomon045802d2015-10-20 07:58:01 -0700455 if (!result) {
456 return nullptr;
457 }
458
459 if (copyKey.isValid()) {
bsalomonb1b01992015-11-18 10:56:08 -0800460 fContext->textureProvider()->assignUniqueKeyToTexture(copyKey, result);
bsalomon045802d2015-10-20 07:58:01 -0700461 this->didCacheCopy(copyKey);
462 }
463 return result;
464}
465
bungeman06ca8ec2016-06-09 08:01:03 -0700466sk_sp<GrFragmentProcessor> GrTextureMaker::createFragmentProcessor(
bsalomonb1b01992015-11-18 10:56:08 -0800467 const SkMatrix& textureMatrix,
468 const SkRect& constraintRect,
469 FilterConstraint filterConstraint,
470 bool coordsLimitedToConstraintRect,
brianosman982eb7f2016-06-06 13:10:58 -0700471 const GrTextureParams::FilterMode* filterOrNullForBicubic,
brianosman500bb3e2016-07-22 10:33:07 -0700472 SkColorSpace* dstColorSpace,
brianosman982eb7f2016-06-06 13:10:58 -0700473 SkSourceGammaTreatment gammaTreatment) {
bsalomonb1b01992015-11-18 10:56:08 -0800474
475 const GrTextureParams::FilterMode* fmForDetermineDomain = filterOrNullForBicubic;
476 if (filterOrNullForBicubic && GrTextureParams::kMipMap_FilterMode == *filterOrNullForBicubic &&
477 kYes_FilterConstraint == filterConstraint) {
478 // TODo: Here we should force a copy restricted to the constraintRect since MIP maps will
479 // read outside the constraint rect. However, as in the adjuster case, we aren't currently
480 // doing that.
481 // We instead we compute the domain as though were bilerping which is only correct if we
482 // only sample level 0.
483 static const GrTextureParams::FilterMode kBilerp = GrTextureParams::kBilerp_FilterMode;
484 fmForDetermineDomain = &kBilerp;
485 }
486
487 GrTextureParams params;
488 if (filterOrNullForBicubic) {
489 params.reset(SkShader::kClamp_TileMode, *filterOrNullForBicubic);
490 } else {
491 // Bicubic doesn't use filtering for it's texture accesses.
492 params.reset(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode);
493 }
brianosman982eb7f2016-06-06 13:10:58 -0700494 SkAutoTUnref<GrTexture> texture(this->refTextureForParams(params, gammaTreatment));
bsalomonb1b01992015-11-18 10:56:08 -0800495 if (!texture) {
496 return nullptr;
497 }
498 SkRect domain;
499 DomainMode domainMode =
500 determine_domain_mode(constraintRect, filterConstraint, coordsLimitedToConstraintRect,
501 texture->width(), texture->height(), nullptr, fmForDetermineDomain,
502 &domain);
503 SkASSERT(kTightCopy_DomainMode != domainMode);
504 SkMatrix normalizedTextureMatrix = textureMatrix;
505 normalizedTextureMatrix.postIDiv(texture->width(), texture->height());
brianosman54f30c12016-07-18 10:53:52 -0700506 sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(this->getColorSpace(),
brianosman51924752016-09-12 08:50:19 -0700507 dstColorSpace);
brianosman54f30c12016-07-18 10:53:52 -0700508 return create_fp_for_domain_and_filter(texture, std::move(colorSpaceXform),
509 normalizedTextureMatrix, domainMode, domain,
bsalomonb1b01992015-11-18 10:56:08 -0800510 filterOrNullForBicubic);
511}
512
brianosman982eb7f2016-06-06 13:10:58 -0700513GrTexture* GrTextureMaker::generateTextureForParams(const CopyParams& copyParams, bool willBeMipped,
514 SkSourceGammaTreatment gammaTreatment) {
515 SkAutoTUnref<GrTexture> original(this->refOriginalTexture(willBeMipped, gammaTreatment));
bsalomon100b8f82015-10-28 08:37:44 -0700516 if (!original) {
517 return nullptr;
bsalomon045802d2015-10-20 07:58:01 -0700518 }
bsalomon89fe56b2015-10-29 10:49:28 -0700519 return copy_on_gpu(original, nullptr, copyParams);
bsalomon045802d2015-10-20 07:58:01 -0700520}