Remove GrTextureProducer::DetermineDomainMode.
We now rely on GrTextureEffect and GrBicbicEffect
to determine if shader-based tiling is required.
GrTextureProducer is still responsible for noticing that
the proxy is approximate because GrTextureEffect doesn't
consider that in its basic Make() factory (as opposed to
MakeSubset()).
Change-Id: I8e1aeb9edbcfa73ea0bf80b5256ee1ca21fe9c81
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/301985
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/GrTextureAdjuster.cpp b/src/gpu/GrTextureAdjuster.cpp
index e83ef0a..59e7cd8 100644
--- a/src/gpu/GrTextureAdjuster.cpp
+++ b/src/gpu/GrTextureAdjuster.cpp
@@ -94,27 +94,12 @@
}
SkASSERT(view.asTextureProxy());
- SkRect domain;
- DomainMode domainMode =
- DetermineDomainMode(constraintRect, filterConstraint, coordsLimitedToConstraintRect,
- view.proxy(), 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 &&
- GrSamplerState::Filter::kMipMap == *filterOrNullForBicubic);
- static const GrSamplerState::Filter kBilerp = GrSamplerState::Filter::kBilerp;
- domainMode =
- DetermineDomainMode(constraintRect, filterConstraint, coordsLimitedToConstraintRect,
- view.proxy(), &kBilerp, &domain);
- SkASSERT(kTightCopy_DomainMode != domainMode);
- }
- SkASSERT(kNoDomain_DomainMode == domainMode ||
- (domain.fLeft <= domain.fRight && domain.fTop <= domain.fBottom));
- return this->createFragmentProcessorForSubsetAndFilter(std::move(view), textureMatrix,
- domainMode, domain, wrapX, wrapY,
+ return this->createFragmentProcessorForSubsetAndFilter(std::move(view),
+ textureMatrix,
+ coordsLimitedToConstraintRect,
+ filterConstraint,
+ constraintRect,
+ wrapX,
+ wrapY,
filterOrNullForBicubic);
}
diff --git a/src/gpu/GrTextureMaker.cpp b/src/gpu/GrTextureMaker.cpp
index 7db8b91..bddf275 100644
--- a/src/gpu/GrTextureMaker.cpp
+++ b/src/gpu/GrTextureMaker.cpp
@@ -30,18 +30,6 @@
GrSamplerState::WrapMode wrapX,
GrSamplerState::WrapMode wrapY,
const GrSamplerState::Filter* filterOrNullForBicubic) {
- const GrSamplerState::Filter* fmForDetermineDomain = filterOrNullForBicubic;
- if (filterOrNullForBicubic && GrSamplerState::Filter::kMipMap == *filterOrNullForBicubic &&
- kYes_FilterConstraint == filterConstraint) {
- // TODO: Here we should force a copy restricted to the constraintRect since MIP maps will
- // read outside the constraint rect. However, as in the adjuster case, we aren't currently
- // doing that.
- // We instead we compute the domain as though were bilerping which is only correct if we
- // only sample level 0.
- static const GrSamplerState::Filter kBilerp = GrSamplerState::Filter::kBilerp;
- fmForDetermineDomain = &kBilerp;
- }
-
GrSurfaceProxyView view;
if (filterOrNullForBicubic) {
view = this->view(*filterOrNullForBicubic);
@@ -52,12 +40,12 @@
return nullptr;
}
- SkRect domain;
- DomainMode domainMode =
- DetermineDomainMode(constraintRect, filterConstraint, coordsLimitedToConstraintRect,
- view.proxy(), fmForDetermineDomain, &domain);
- SkASSERT(kTightCopy_DomainMode != domainMode);
- return this->createFragmentProcessorForSubsetAndFilter(std::move(view), textureMatrix,
- domainMode, domain, wrapX, wrapY,
+ return this->createFragmentProcessorForSubsetAndFilter(std::move(view),
+ textureMatrix,
+ coordsLimitedToConstraintRect,
+ filterConstraint,
+ constraintRect,
+ wrapX,
+ wrapY,
filterOrNullForBicubic);
}
diff --git a/src/gpu/GrTextureProducer.cpp b/src/gpu/GrTextureProducer.cpp
index 8bc9427..2a1d6d6 100644
--- a/src/gpu/GrTextureProducer.cpp
+++ b/src/gpu/GrTextureProducer.cpp
@@ -20,148 +20,57 @@
#include "src/gpu/effects/GrBicubicEffect.h"
#include "src/gpu/effects/GrTextureEffect.h"
-/** 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 (i.e., textureContentArea).
- * We can *never* allow filtering to cause bleed of pixels outside this rectangle.
- * - The second rectangle is the constraint rectangle (i.e., constraintRect), 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.
- */
-GrTextureProducer::DomainMode GrTextureProducer::DetermineDomainMode(
- const SkRect& constraintRect,
- FilterConstraint filterConstraint,
- bool coordsLimitedToConstraintRect,
- GrSurfaceProxy* proxy,
- const GrSamplerState::Filter* filterModeOrNullForBicubic,
- SkRect* domainRect) {
- const SkIRect proxyBounds = SkIRect::MakeSize(proxy->dimensions());
-
- SkASSERT(proxyBounds.contains(constraintRect));
-
- const bool proxyIsExact = proxy->isFunctionallyExact();
-
- // If the constraint rectangle contains the whole proxy then no need for a domain.
- if (constraintRect.contains(proxyBounds) && proxyIsExact) {
- return kNoDomain_DomainMode;
- }
-
- bool restrictFilterToRect = (filterConstraint == GrTextureProducer::kYes_FilterConstraint);
-
- // If we can filter outside the constraint rect, and there is no non-content area of the
- // proxy, and we aren't going to generate sample coords outside the constraint rect then we
- // don't need a domain.
- if (!restrictFilterToRect && proxyIsExact && coordsLimitedToConstraintRect) {
- return kNoDomain_DomainMode;
- }
-
- // Get the domain inset based on sampling mode (or bail if mipped). This is used
- // to evaluate whether we will read outside a non-exact proxy's dimensions.
- // TODO: Let GrTextureEffect handle this.
- SkScalar filterHalfWidth = 0.f;
- if (filterModeOrNullForBicubic) {
- switch (*filterModeOrNullForBicubic) {
- case GrSamplerState::Filter::kNearest:
- if (coordsLimitedToConstraintRect) {
- return kNoDomain_DomainMode;
- } else {
- filterHalfWidth = 0.f;
- }
- break;
- case GrSamplerState::Filter::kBilerp:
- filterHalfWidth = .5f;
- break;
- case GrSamplerState::Filter::kMipMap:
- if (restrictFilterToRect || !proxyIsExact) {
- // No domain can save us here.
- return kTightCopy_DomainMode;
- }
- return kNoDomain_DomainMode;
- }
- } else {
- // bicubic does nearest filtering internally.
- filterHalfWidth = 1.5f;
- }
-
- if (restrictFilterToRect) {
- *domainRect = constraintRect;
- } else if (!proxyIsExact) {
- // If we got here then: proxy is not exact, 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 proxy.
- // We will only set the sides that are required.
-
- *domainRect = SkRectPriv::MakeLargest();
- 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 (proxyBounds.fRight - filterHalfWidth < constraintRect.fRight) {
- domainRect->fRight = proxyBounds.fRight;
- needContentAreaConstraint = true;
- }
- if (proxyBounds.fBottom - filterHalfWidth < constraintRect.fBottom) {
- domainRect->fBottom = proxyBounds.fBottom;
- needContentAreaConstraint = true;
- }
- if (!needContentAreaConstraint) {
- return kNoDomain_DomainMode;
- }
- }
- } else {
- return kNoDomain_DomainMode;
- }
-
- if (!filterModeOrNullForBicubic) {
- // Bicubic doesn't yet rely on GrTextureEffect to do this insetting.
- domainRect->inset(0.5f, 0.5f);
- 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);
- }
- }
-
- return kDomain_DomainMode;
-}
-
std::unique_ptr<GrFragmentProcessor> GrTextureProducer::createFragmentProcessorForSubsetAndFilter(
GrSurfaceProxyView view,
const SkMatrix& textureMatrix,
- DomainMode domainMode,
- const SkRect& domain,
+ bool coordsLimitedToConstraintRect,
+ FilterConstraint filterConstraint,
+ const SkRect& constraintRect,
GrSamplerState::WrapMode wrapX,
GrSamplerState::WrapMode wrapY,
const GrSamplerState::Filter* filterOrNullForBicubic) {
- SkASSERT(kTightCopy_DomainMode != domainMode);
- SkASSERT(view.asTextureProxy());
+ SkRect tempSubset;
+
+ const SkRect* subset = nullptr;
+ if (filterConstraint == kYes_FilterConstraint) {
+ subset = &constraintRect;
+ } else if (!view.proxy()->isFullyLazy() && !view.proxy()->isFunctionallyExact()) {
+ tempSubset = view.proxy()->getBoundsRect();
+ subset = &tempSubset;
+ }
+
const auto& caps = *fContext->priv().caps();
- SkAlphaType srcAlphaType = this->alphaType();
if (filterOrNullForBicubic) {
GrSamplerState samplerState(wrapX, wrapY, *filterOrNullForBicubic);
- if (kNoDomain_DomainMode == domainMode) {
- return GrTextureEffect::Make(std::move(view), srcAlphaType, textureMatrix, samplerState,
- caps);
+ if (subset) {
+ if (coordsLimitedToConstraintRect) {
+ return GrTextureEffect::MakeSubset(std::move(view), this->alphaType(),
+ textureMatrix, samplerState, *subset,
+ constraintRect, caps);
+ } else {
+ return GrTextureEffect::MakeSubset(std::move(view), this->alphaType(),
+ textureMatrix, samplerState, *subset, caps);
+ }
+ } else {
+ return GrTextureEffect::Make(std::move(view), this->alphaType(), textureMatrix,
+ samplerState, caps);
}
- return GrTextureEffect::MakeSubset(std::move(view), srcAlphaType, textureMatrix,
- samplerState, domain, caps);
} else {
static constexpr auto kDir = GrBicubicEffect::Direction::kXY;
static constexpr auto kKernel = GrBicubicEffect::Kernel::kMitchell;
- const auto& caps = *fContext->priv().caps();
- if (kDomain_DomainMode == domainMode) {
- return GrBicubicEffect::MakeSubset(std::move(view), srcAlphaType, textureMatrix, wrapX,
- wrapY, domain, kKernel, kDir, caps);
+ if (subset) {
+ if (coordsLimitedToConstraintRect) {
+ return GrBicubicEffect::MakeSubset(std::move(view), this->alphaType(),
+ textureMatrix, wrapX, wrapY, *subset,
+ constraintRect, kKernel, kDir, caps);
+ } else {
+ return GrBicubicEffect::MakeSubset(std::move(view), this->alphaType(),
+ textureMatrix, wrapX, wrapY, *subset, kKernel,
+ kDir, caps);
+ }
} else {
- return GrBicubicEffect::Make(std::move(view), srcAlphaType, textureMatrix, wrapX, wrapY,
- kKernel, kDir, caps);
+ return GrBicubicEffect::Make(std::move(view), this->alphaType(), textureMatrix, wrapX,
+ wrapY, kKernel, kDir, caps);
}
}
}
diff --git a/src/gpu/GrTextureProducer.h b/src/gpu/GrTextureProducer.h
index 4a13357..657553e 100644
--- a/src/gpu/GrTextureProducer.h
+++ b/src/gpu/GrTextureProducer.h
@@ -32,16 +32,16 @@
*/
class GrTextureProducer : public SkNoncopyable {
public:
- virtual ~GrTextureProducer() {}
+ virtual ~GrTextureProducer() = default;
enum FilterConstraint {
kYes_FilterConstraint,
kNo_FilterConstraint,
};
- /**
+ /**
* Helper for creating a fragment processor to sample the texture with a given filtering mode.
- * It attempts to avoid making texture copies or using domains whenever possible.
+ * It attempts to avoid making texture copies or using shader tiling whenever possible.
*
* @param textureMatrix Matrix used to access the texture. It is applied to
* the local coords. The post-transformed coords should
@@ -89,29 +89,15 @@
virtual bool isPlanar() const { return false; }
protected:
- friend class GrTextureProducer_TestAccess;
-
GrTextureProducer(GrRecordingContext* context, const GrImageInfo& imageInfo)
: fContext(context), fImageInfo(imageInfo) {}
- enum DomainMode {
- kNoDomain_DomainMode,
- kDomain_DomainMode,
- kTightCopy_DomainMode
- };
-
- static DomainMode DetermineDomainMode(const SkRect& constraintRect,
- FilterConstraint filterConstraint,
- bool coordsLimitedToConstraintRect,
- GrSurfaceProxy*,
- const GrSamplerState::Filter* filterModeOrNullForBicubic,
- SkRect* domainRect);
-
std::unique_ptr<GrFragmentProcessor> createFragmentProcessorForSubsetAndFilter(
GrSurfaceProxyView view,
const SkMatrix& textureMatrix,
- DomainMode,
- const SkRect& domain,
+ bool coordsLimitedToConstraintRect,
+ FilterConstraint filterConstraint,
+ const SkRect& constraintRect,
GrSamplerState::WrapMode wrapX,
GrSamplerState::WrapMode wrapY,
const GrSamplerState::Filter* filterOrNullForBicubic);
diff --git a/src/gpu/effects/GrBicubicEffect.cpp b/src/gpu/effects/GrBicubicEffect.cpp
index 1df8006..385dec0 100644
--- a/src/gpu/effects/GrBicubicEffect.cpp
+++ b/src/gpu/effects/GrBicubicEffect.cpp
@@ -14,6 +14,7 @@
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
#include "src/gpu/glsl/GrGLSLUniformHandler.h"
+#include <cmath>
class GrBicubicEffect::Impl : public GrGLSLFragmentProcessor {
public:
@@ -180,6 +181,34 @@
new GrBicubicEffect(std::move(fp), kernel, direction, clamp)));
}
+std::unique_ptr<GrFragmentProcessor> GrBicubicEffect::MakeSubset(
+ GrSurfaceProxyView view,
+ SkAlphaType alphaType,
+ const SkMatrix& matrix,
+ const GrSamplerState::WrapMode wrapX,
+ const GrSamplerState::WrapMode wrapY,
+ const SkRect& subset,
+ const SkRect& domain,
+ Kernel kernel,
+ Direction direction,
+ const GrCaps& caps) {
+ auto lowerBound = [](float x) { return std::floor(x - 1.5f) + 0.5f; };
+ auto upperBound = [](float x) { return std::floor(x + 1.5f) - 0.5f; };
+ SkRect expandedDomain {
+ lowerBound(domain.fLeft) ,
+ upperBound(domain.fRight) ,
+ lowerBound(domain.fTop) ,
+ upperBound(domain.fBottom)
+ };
+ GrSamplerState sampler(wrapX, wrapY, GrSamplerState::Filter::kNearest);
+ std::unique_ptr<GrFragmentProcessor> fp;
+ fp = GrTextureEffect::MakeSubset(
+ std::move(view), alphaType, SkMatrix::I(), sampler, subset, expandedDomain, caps);
+ auto clamp = kPremul_SkAlphaType == alphaType ? Clamp::kPremul : Clamp::kUnpremul;
+ return GrMatrixEffect::Make(matrix, std::unique_ptr<GrFragmentProcessor>(
+ new GrBicubicEffect(std::move(fp), kernel, direction, clamp)));
+}
+
std::unique_ptr<GrFragmentProcessor> GrBicubicEffect::Make(std::unique_ptr<GrFragmentProcessor> fp,
SkAlphaType alphaType,
const SkMatrix& matrix,
diff --git a/src/gpu/effects/GrBicubicEffect.h b/src/gpu/effects/GrBicubicEffect.h
index b9b420c..a0de090 100644
--- a/src/gpu/effects/GrBicubicEffect.h
+++ b/src/gpu/effects/GrBicubicEffect.h
@@ -75,6 +75,21 @@
const GrCaps&);
/**
+ * Same as above but provides a known 'domain' that bounds the coords at which bicubic sampling
+ * occurs. Note that this is a bound on the coords after transformed by the matrix parameter.
+ */
+ static std::unique_ptr<GrFragmentProcessor> MakeSubset(GrSurfaceProxyView view,
+ SkAlphaType,
+ const SkMatrix&,
+ const GrSamplerState::WrapMode wrapX,
+ const GrSamplerState::WrapMode wrapY,
+ const SkRect& subset,
+ const SkRect& domain,
+ Kernel,
+ Direction,
+ const GrCaps&);
+
+ /**
* Make a bicubic filter of a another fragment processor. The bicubic filter assumes that the
* discrete samples of the provided processor are at half-integer coords.
*/