Index: src/gpu/GrTextureParamsAdjuster.cpp |
diff --git a/src/gpu/GrTextureParamsAdjuster.cpp b/src/gpu/GrTextureParamsAdjuster.cpp |
index 579cf96ef36d30823a70b491cc0015e6813be116..d3daafc0932e6d1bff9d6aea2a47d528878f2ee0 100644 |
--- a/src/gpu/GrTextureParamsAdjuster.cpp |
+++ b/src/gpu/GrTextureParamsAdjuster.cpp |
@@ -19,6 +19,7 @@ |
#include "SkCanvas.h" |
#include "SkGr.h" |
#include "SkGrPriv.h" |
+#include "effects/GrBicubicEffect.h" |
#include "effects/GrTextureDomain.h" |
typedef GrTextureProducer::CopyParams CopyParams; |
@@ -171,6 +172,176 @@ GrTexture* GrTextureAdjuster::refTextureSafeForParams(const GrTextureParams& par |
return result; |
} |
+enum DomainMode { |
+ kNoDomain_DomainMode, |
+ kDomain_DomainMode, |
+ kTightCopy_DomainMode |
+}; |
+ |
+/** Determines whether a texture domain is necessary and if so what domain to use. In the case of |
+ mip maps it may indicate that a copy must be made to avoid filtering outside the constraint |
+ rectangle or the content area of the texture. */ |
+static DomainMode determine_domain_mode( |
robertphillips
2015/11/05 20:13:24
tab these over one to avoid lining up with the cod
bsalomon
2015/11/06 15:24:26
Done.
|
+ const SkRect& constraintRect, |
+ GrTextureAdjuster::FilterConstraint filterConstraint, |
+ bool coordsLimitedContraintRect, |
+ int texW, int texH, |
+ const SkIRect* textureContentArea, |
+ const GrTextureParams::FilterMode* filterModeOrNullForBicubic, |
+ SkRect* domainRect) { |
robertphillips
2015/11/05 20:13:24
... or maybe a '\n' here ?
bsalomon
2015/11/06 15:24:26
Done.
|
+ SkASSERT(SkRect::MakeIWH(texW, texH).contains(constraintRect)); |
+ // We only expect a content area rect if there is some non-content area. |
+ SkASSERT(!textureContentArea || |
+ (!textureContentArea->contains(SkIRect::MakeWH(texW, texH)) && |
+ SkRect::Make(*textureContentArea).contains(constraintRect))); |
+ |
+ SkRect textureBounds = SkRect::MakeIWH(texW, texH); |
+ // If the src rectangle contains the whole texture then no need for a domain. |
+ if (constraintRect.contains(textureBounds)) { |
+ return kNoDomain_DomainMode; |
+ } |
+ |
+ bool restrictFilterToRect = (filterConstraint == GrTextureAdjuster::kYes_FilterConstraint); |
+ |
+ // If we can filter outside the constraint rect, and there is no non-content area of the |
+ // texture, and we aren't going to generate sample coords outside the constraint rect then we |
+ // don't need a domain. |
+ if (!restrictFilterToRect && !textureContentArea && coordsLimitedContraintRect) { |
+ return kNoDomain_DomainMode; |
+ } |
+ |
+ // Get the domain inset based on sampling mode (or bail if mipped) |
+ SkScalar filterHalfWidth; |
+ if (filterModeOrNullForBicubic) { |
+ switch (*filterModeOrNullForBicubic) { |
+ case GrTextureParams::kNone_FilterMode: |
+ if (coordsLimitedContraintRect) { |
+ return kNoDomain_DomainMode; |
+ } else { |
+ filterHalfWidth = 0.f; |
+ } |
+ break; |
+ case GrTextureParams::kBilerp_FilterMode: |
+ filterHalfWidth = 1.f; |
+ break; |
+ case GrTextureParams::kMipMap_FilterMode: |
+ // No domain can save use here. |
+ return kTightCopy_DomainMode; |
+ } |
+ } else { |
+ // bicubic does nearest filtering internally. |
+ filterHalfWidth = 2.f; |
+ } |
+ |
robertphillips
2015/11/05 20:13:24
// We will inset the domain half a pixel b.c. ...
bsalomon
2015/11/06 15:24:25
Done.
|
+ static const SkScalar kDomainInset = 0.5f; |
robertphillips
2015/11/05 20:13:24
can -> to ?
bsalomon
2015/11/06 15:24:26
Done.
|
+ // Figure out the limits of pixels we're allowed can sample from. |
+ // Unless we know the amount of outset and the texture matrix we have to conservatively enforce |
+ // the domain. |
+ if (restrictFilterToRect) { |
+ domainRect->fLeft = constraintRect.fLeft + kDomainInset; |
+ domainRect->fTop = constraintRect.fTop + kDomainInset; |
+ domainRect->fRight = constraintRect.fRight - kDomainInset; |
+ domainRect->fBottom = constraintRect.fBottom - kDomainInset; |
+ } else if (textureContentArea) { |
+ // If we got here then: there is a textureContentArea, the coords are limited to the |
+ // constraint rect, and we're allowed to filter across the constraint rect boundary. So |
robertphillips
2015/11/05 20:13:24
from -> to ?
bsalomon
2015/11/06 15:24:26
Done.
|
+ // we check whether the filter would reach from the edge of the content area. |
+ bool needContentAreaConstraint = false; |
+ // We will only set the sides that are required. |
+ domainRect->setLargest(); |
+ if (textureContentArea->fLeft > 0 && |
+ textureContentArea->fLeft + filterHalfWidth > constraintRect.fLeft) { |
+ domainRect->fLeft = textureContentArea->fLeft + kDomainInset; |
+ needContentAreaConstraint = true; |
+ } |
+ if (textureContentArea->fTop > 0 && |
+ textureContentArea->fTop + filterHalfWidth > constraintRect.fTop) { |
+ domainRect->fTop = textureContentArea->fTop + kDomainInset; |
+ needContentAreaConstraint = true; |
+ } |
+ if (textureContentArea->fRight < texW && |
+ textureContentArea->fRight - filterHalfWidth < constraintRect.fRight) { |
+ domainRect->fRight = textureContentArea->fRight - kDomainInset; |
+ needContentAreaConstraint = true; |
+ } |
+ if (textureContentArea->fBottom < texW && |
+ textureContentArea->fBottom - filterHalfWidth < constraintRect.fBottom) { |
+ domainRect->fBottom = textureContentArea->fBottom - kDomainInset; |
+ needContentAreaConstraint = true; |
+ } |
+ if (!needContentAreaConstraint) { |
+ return kNoDomain_DomainMode; |
+ } |
+ } else { |
+ return kNoDomain_DomainMode; |
+ } |
+ |
+ if (domainRect->fLeft > domainRect->fRight) { |
+ domainRect->fLeft = domainRect->fRight = SkScalarAve(domainRect->fLeft, domainRect->fRight); |
+ } |
+ if (domainRect->fTop > domainRect->fBottom) { |
+ domainRect->fTop = domainRect->fBottom = SkScalarAve(domainRect->fTop, domainRect->fBottom); |
+ } |
robertphillips
2015/11/05 20:13:24
What happens to the sides that are still out at th
bsalomon
2015/11/06 15:24:26
They'd still be really large (in abs value). This
|
+ domainRect->fLeft /= texW; |
+ domainRect->fTop /= texH; |
+ domainRect->fRight /= texW; |
+ domainRect->fBottom /= texH; |
+ return kDomain_DomainMode; |
+} |
+ |
+const GrFragmentProcessor* GrTextureAdjuster::createFragmentProcessor( |
+ const SkMatrix& textureMatrix, |
+ const SkRect& constraintRect, |
+ FilterConstraint filterConstraint, |
+ bool coordsLimitedToConstraintRect, |
+ const GrTextureParams::FilterMode* filterOrNullForBicubic) { |
+ |
+ const SkIRect* contentArea = this->contentArea(); |
+ |
+ SkRect domain; |
+ GrTexture* texture = this->originalTexture(); |
+ DomainMode domainMode = |
+ determine_domain_mode(constraintRect, filterConstraint, coordsLimitedToConstraintRect, |
+ texture->width(), texture->height(), |
+ contentArea, filterOrNullForBicubic, |
+ &domain); |
+ if (kTightCopy_DomainMode == domainMode) { |
+ // TODO: Copy the texture and adjust the texture matrix (both parts need to consider |
+ // non-int constraint rect) |
+ // For now: treat as bilerp and ignore what goes on above level 0. |
+ SkASSERT(filterOrNullForBicubic && |
+ GrTextureParams::kMipMap_FilterMode == *filterOrNullForBicubic); |
+ static const GrTextureParams::FilterMode kBilerp = GrTextureParams::kBilerp_FilterMode; |
+ domainMode = |
+ determine_domain_mode(constraintRect, filterConstraint, coordsLimitedToConstraintRect, |
+ texture->width(), texture->height(), |
+ contentArea, &kBilerp, &domain); |
+ SkASSERT(kTightCopy_DomainMode != domainMode); |
+ filterOrNullForBicubic = &kBilerp; |
+ } |
+ SkASSERT(kNoDomain_DomainMode == domainMode || |
+ (domain.fLeft <= domain.fRight && domain.fTop <= domain.fBottom)); |
+ if (filterOrNullForBicubic) { |
+ if (kDomain_DomainMode == domainMode) { |
+ SkASSERT(*filterOrNullForBicubic != GrTextureParams::kMipMap_FilterMode); |
+ return GrTextureDomainEffect::Create(texture, textureMatrix, domain, |
+ GrTextureDomain::kClamp_Mode, |
+ *filterOrNullForBicubic); |
+ } else { |
+ GrTextureParams params(SkShader::kClamp_TileMode, *filterOrNullForBicubic); |
+ return GrSimpleTextureEffect::Create(texture, textureMatrix, params); |
+ } |
+ } else { |
+ if (kDomain_DomainMode == domainMode) { |
+ return GrBicubicEffect::Create(texture, textureMatrix, domain); |
+ } else { |
+ static const SkShader::TileMode kClampClamp[] = |
+ { SkShader::kClamp_TileMode, SkShader::kClamp_TileMode }; |
+ return GrBicubicEffect::Create(texture, textureMatrix, kClampClamp); |
+ } |
+ } |
+} |
+ |
////////////////////////////////////////////////////////////////////////////// |
GrTexture* GrTextureMaker::refTextureForParams(GrContext* ctx, const GrTextureParams& params) { |