| Index: src/gpu/GrTextureParamsAdjuster.cpp
|
| diff --git a/src/gpu/GrTextureParamsAdjuster.cpp b/src/gpu/GrTextureParamsAdjuster.cpp
|
| index 579cf96ef36d30823a70b491cc0015e6813be116..b98a126971de0836d666226a184179d50588632c 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;
|
| @@ -131,7 +132,7 @@ GrTexture* GrTextureAdjuster::refTextureSafeForParams(const GrTextureParams& par
|
| GrTexture* texture = this->originalTexture();
|
| GrContext* context = texture->getContext();
|
| CopyParams copyParams;
|
| - const SkIRect* contentArea = this->contentArea();
|
| + const SkIRect* contentArea = this->contentAreaOrNull();
|
|
|
| if (contentArea && GrTextureParams::kMipMap_FilterMode == params.filterMode()) {
|
| // If we generate a MIP chain for texture it will read pixel values from outside the content
|
| @@ -171,6 +172,211 @@ 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. There are two
|
| + * rectangles to consider:
|
| + * - The first is the content area specified by the texture adjuster. We can *never* allow
|
| + * filtering to cause bleed of pixels outside this rectangle.
|
| + * - The second rectangle is the constraint rectangle, which is known to be contained by the
|
| + * content area. The filterConstraint specifies whether we are allowed to bleed across this
|
| + * rect.
|
| + *
|
| + * We want to avoid using a domain if possible. We consider the above rectangles, the filter type,
|
| + * and whether the coords generated by the draw would all fall within the constraint rect. If the
|
| + * latter is true we only need to consider whether the filter would extend beyond the rects.
|
| + */
|
| +static DomainMode determine_domain_mode(
|
| + const SkRect& constraintRect,
|
| + GrTextureAdjuster::FilterConstraint filterConstraint,
|
| + bool coordsLimitedToConstraintRect,
|
| + int texW, int texH,
|
| + const SkIRect* textureContentArea,
|
| + const GrTextureParams::FilterMode* filterModeOrNullForBicubic,
|
| + SkRect* domainRect) {
|
| +
|
| + 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 && coordsLimitedToConstraintRect) {
|
| + return kNoDomain_DomainMode;
|
| + }
|
| +
|
| + // Get the domain inset based on sampling mode (or bail if mipped)
|
| + SkScalar filterHalfWidth = 0.f;
|
| + if (filterModeOrNullForBicubic) {
|
| + switch (*filterModeOrNullForBicubic) {
|
| + case GrTextureParams::kNone_FilterMode:
|
| + if (coordsLimitedToConstraintRect) {
|
| + return kNoDomain_DomainMode;
|
| + } else {
|
| + filterHalfWidth = 0.f;
|
| + }
|
| + break;
|
| + case GrTextureParams::kBilerp_FilterMode:
|
| + filterHalfWidth = .5f;
|
| + break;
|
| + case GrTextureParams::kMipMap_FilterMode:
|
| + // No domain can save use here.
|
| + return kTightCopy_DomainMode;
|
| + }
|
| + } else {
|
| + // bicubic does nearest filtering internally.
|
| + filterHalfWidth = 1.5f;
|
| + }
|
| +
|
| + // Both bilerp and bicubic use bilinear filtering and so need to be clamped to the center
|
| + // of the edge texel. Pinning to the texel center has no impact on nearest mode and MIP-maps
|
| +
|
| + static const SkScalar kDomainInset = 0.5f;
|
| + // Figure out the limits of pixels we're allowed to 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
|
| + // we check whether the filter would reach across the edge of the content area.
|
| + // We will only set the sides that are required.
|
| +
|
| + domainRect->setLargest();
|
| + if (coordsLimitedToConstraintRect) {
|
| + // We may be able to use the fact that the texture coords are limited to the constraint
|
| + // rect in order to avoid having to add a domain.
|
| + bool needContentAreaConstraint = false;
|
| + 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 < texH &&
|
| + textureContentArea->fBottom - filterHalfWidth < constraintRect.fBottom) {
|
| + domainRect->fBottom = textureContentArea->fBottom - kDomainInset;
|
| + needContentAreaConstraint = true;
|
| + }
|
| + if (!needContentAreaConstraint) {
|
| + return kNoDomain_DomainMode;
|
| + }
|
| + } else {
|
| + // Our sample coords for the texture are allowed to be outside the constraintRect so we
|
| + // don't consider it when computing the domain.
|
| + if (textureContentArea->fLeft != 0) {
|
| + domainRect->fLeft = textureContentArea->fLeft + kDomainInset;
|
| + }
|
| + if (textureContentArea->fTop != 0) {
|
| + domainRect->fTop = textureContentArea->fTop + kDomainInset;
|
| + }
|
| + if (textureContentArea->fRight != texW) {
|
| + domainRect->fRight = textureContentArea->fRight - kDomainInset;
|
| + }
|
| + if (textureContentArea->fBottom != texH) {
|
| + domainRect->fBottom = textureContentArea->fBottom - kDomainInset;
|
| + }
|
| + }
|
| + } 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);
|
| + }
|
| + 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->contentAreaOrNull();
|
| +
|
| + 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.
|
| +
|
| + // We only expect MIP maps to require a tight copy.
|
| + 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) {
|
|
|