GrTextureEffect handles insets for float rects as well as integer rects.
Fix insets for clamp/nearest case. Change-Id: I1fa2f6d172fdac59836ae73c7a5fec0d0cde020c Reviewed-on: https://skia-review.googlesource.com/c/skia/+/268397 Commit-Queue: Brian Salomon <bsalomon@google.com> Reviewed-by: Michael Ludwig <michaelludwig@google.com>
This commit is contained in:
parent
e13cbc3f15
commit
ed729f99af
@ -110,7 +110,9 @@ GrTextureProducer::DomainMode GrTextureProducer::DetermineDomainMode(
|
||||
return kNoDomain_DomainMode;
|
||||
}
|
||||
|
||||
// Get the domain inset based on sampling mode (or bail if mipped)
|
||||
// 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) {
|
||||
@ -136,15 +138,8 @@ GrTextureProducer::DomainMode GrTextureProducer::DetermineDomainMode(
|
||||
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 = constraintRect.makeInset(kDomainInset, kDomainInset);
|
||||
*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
|
||||
@ -157,32 +152,34 @@ GrTextureProducer::DomainMode GrTextureProducer::DetermineDomainMode(
|
||||
// rect in order to avoid having to add a domain.
|
||||
bool needContentAreaConstraint = false;
|
||||
if (proxyBounds.fRight - filterHalfWidth < constraintRect.fRight) {
|
||||
domainRect->fRight = proxyBounds.fRight - kDomainInset;
|
||||
domainRect->fRight = proxyBounds.fRight;
|
||||
needContentAreaConstraint = true;
|
||||
}
|
||||
if (proxyBounds.fBottom - filterHalfWidth < constraintRect.fBottom) {
|
||||
domainRect->fBottom = proxyBounds.fBottom - kDomainInset;
|
||||
domainRect->fBottom = proxyBounds.fBottom;
|
||||
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.
|
||||
domainRect->fRight = proxyBounds.fRight - kDomainInset;
|
||||
domainRect->fBottom = proxyBounds.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);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -937,29 +937,15 @@ void SkGpuDevice::drawBitmapTile(const SkBitmap& bitmap,
|
||||
|
||||
const auto& caps = *this->caps();
|
||||
if (needsTextureDomain && (SkCanvas::kStrict_SrcRectConstraint == constraint)) {
|
||||
// Use a constrained texture domain to avoid color bleeding
|
||||
SkRect domain;
|
||||
if (srcRect.width() > SK_Scalar1) {
|
||||
domain.fLeft = srcRect.fLeft + 0.5f;
|
||||
domain.fRight = srcRect.fRight - 0.5f;
|
||||
} else {
|
||||
domain.fLeft = domain.fRight = srcRect.centerX();
|
||||
}
|
||||
if (srcRect.height() > SK_Scalar1) {
|
||||
domain.fTop = srcRect.fTop + 0.5f;
|
||||
domain.fBottom = srcRect.fBottom - 0.5f;
|
||||
} else {
|
||||
domain.fTop = domain.fBottom = srcRect.centerY();
|
||||
}
|
||||
if (bicubic) {
|
||||
static constexpr auto kDir = GrBicubicEffect::Direction::kXY;
|
||||
fp = GrBicubicEffect::Make(std::move(proxy), texMatrix, domain, kDir, srcAlphaType);
|
||||
fp = GrBicubicEffect::Make(std::move(proxy), texMatrix, srcRect, kDir, srcAlphaType);
|
||||
} else {
|
||||
GrSurfaceOrigin origin = proxy->origin();
|
||||
GrSwizzle swizzle = proxy->textureSwizzle();
|
||||
GrSurfaceProxyView view(std::move(proxy), origin, swizzle);
|
||||
fp = GrTextureEffect::MakeSubset(std::move(view), srcAlphaType, texMatrix, samplerState,
|
||||
domain, caps);
|
||||
fp = GrTextureEffect::MakeSubset(std::move(view), srcAlphaType, texMatrix,
|
||||
samplerState, srcRect, caps);
|
||||
}
|
||||
} else if (bicubic) {
|
||||
SkASSERT(GrSamplerState::Filter::kNearest == samplerState.filter());
|
||||
|
@ -78,7 +78,6 @@ GrTextureEffect::Sampling::Sampling(GrSamplerState sampler, SkISize size, const
|
||||
GrTextureEffect::Sampling::Sampling(const GrSurfaceProxy& proxy,
|
||||
GrSamplerState sampler,
|
||||
const SkRect& subset,
|
||||
bool adjustForFilter,
|
||||
const SkRect* domain,
|
||||
const GrCaps& caps) {
|
||||
using Mode = GrSamplerState::WrapMode;
|
||||
@ -91,9 +90,8 @@ GrTextureEffect::Sampling::Sampling(const GrSurfaceProxy& proxy,
|
||||
Filter fFilter;
|
||||
};
|
||||
|
||||
auto resolve = [adjustForFilter, filter = sampler.filter(), &caps](int size, Mode mode,
|
||||
Span subset, Span domain) {
|
||||
float inset;
|
||||
auto resolve = [filter = sampler.filter(), &caps](int size, Mode mode, Span subset,
|
||||
Span domain) {
|
||||
Result1D r;
|
||||
r.fFilter = filter;
|
||||
bool canDoHW = (mode != Mode::kClampToBorder || caps.clampToBorderSupport()) &&
|
||||
@ -104,10 +102,27 @@ GrTextureEffect::Sampling::Sampling(const GrSurfaceProxy& proxy,
|
||||
return r;
|
||||
}
|
||||
|
||||
inset = (adjustForFilter && filter != Filter::kNearest) ? 0.5 : 0;
|
||||
auto insetSubset = subset.makeInset(inset);
|
||||
|
||||
if (canDoHW && insetSubset.contains(domain)) {
|
||||
bool domainIsSafe = false;
|
||||
Span insetSubset;
|
||||
if (filter == Filter::kNearest) {
|
||||
Span isubset{sk_float_floor(subset.fA), sk_float_ceil(subset.fB)};
|
||||
if (domain.fA > isubset.fA && domain.fB < isubset.fB) {
|
||||
domainIsSafe = true;
|
||||
}
|
||||
if (mode == Mode::kClamp) {
|
||||
// This inset prevents sampling neighboring texels that could occur when
|
||||
// texture coords fall exactly at texel boundaries (depending on precision
|
||||
// and GPU-specific snapping at the boundary).
|
||||
insetSubset = isubset.makeInset(0.5f);
|
||||
} else {
|
||||
// TODO: Handle other modes properly in this case.
|
||||
insetSubset = subset;
|
||||
}
|
||||
} else {
|
||||
insetSubset = subset.makeInset(0.5f);
|
||||
domainIsSafe = insetSubset.contains(domain);
|
||||
}
|
||||
if (canDoHW && domainIsSafe) {
|
||||
r.fShaderMode = ShaderMode::kNone;
|
||||
r.fHWMode = mode;
|
||||
return r;
|
||||
@ -173,8 +188,7 @@ std::unique_ptr<GrFragmentProcessor> GrTextureEffect::MakeTexelSubset(GrSurfaceP
|
||||
GrSamplerState sampler,
|
||||
const SkIRect& subset,
|
||||
const GrCaps& caps) {
|
||||
Sampling sampling(*view.proxy(), sampler, SkRect::Make(subset), true, nullptr, caps);
|
||||
|
||||
Sampling sampling(*view.proxy(), sampler, SkRect::Make(subset), nullptr, caps);
|
||||
return std::unique_ptr<GrFragmentProcessor>(
|
||||
new GrTextureEffect(std::move(view), alphaType, matrix, sampling));
|
||||
}
|
||||
@ -186,7 +200,7 @@ std::unique_ptr<GrFragmentProcessor> GrTextureEffect::MakeTexelSubset(GrSurfaceP
|
||||
const SkIRect& subset,
|
||||
const SkRect& domain,
|
||||
const GrCaps& caps) {
|
||||
Sampling sampling(*view.proxy(), sampler, SkRect::Make(subset), true, &domain, caps);
|
||||
Sampling sampling(*view.proxy(), sampler, SkRect::Make(subset), &domain, caps);
|
||||
return std::unique_ptr<GrFragmentProcessor>(
|
||||
new GrTextureEffect(std::move(view), alphaType, matrix, sampling));
|
||||
}
|
||||
@ -197,7 +211,7 @@ std::unique_ptr<GrFragmentProcessor> GrTextureEffect::MakeSubset(GrSurfaceProxyV
|
||||
GrSamplerState sampler,
|
||||
const SkRect& subset,
|
||||
const GrCaps& caps) {
|
||||
Sampling sampling(*view.proxy(), sampler, subset, false, nullptr, caps);
|
||||
Sampling sampling(*view.proxy(), sampler, subset, nullptr, caps);
|
||||
return std::unique_ptr<GrFragmentProcessor>(
|
||||
new GrTextureEffect(std::move(view), alphaType, matrix, sampling));
|
||||
}
|
||||
@ -209,7 +223,7 @@ std::unique_ptr<GrFragmentProcessor> GrTextureEffect::MakeSubset(GrSurfaceProxyV
|
||||
const SkRect& subset,
|
||||
const SkRect& domain,
|
||||
const GrCaps& caps) {
|
||||
Sampling sampling(*view.proxy(), sampler, subset, false, &domain, caps);
|
||||
Sampling sampling(*view.proxy(), sampler, subset, &domain, caps);
|
||||
return std::unique_ptr<GrFragmentProcessor>(
|
||||
new GrTextureEffect(std::move(view), alphaType, matrix, sampling));
|
||||
}
|
||||
|
@ -61,9 +61,6 @@ public:
|
||||
|
||||
/**
|
||||
* This is similar to MakeTexelSubset but takes a float rather than integer subset rect.
|
||||
* No adjustment is done for filtering, the texture coordinates are limited to the
|
||||
* unmodified subset. The subset should be unnormalized. The effect will apply texture
|
||||
* coordinate normalization after subset restriction (logically).
|
||||
*/
|
||||
static std::unique_ptr<GrFragmentProcessor> MakeSubset(GrSurfaceProxyView,
|
||||
SkAlphaType,
|
||||
@ -108,7 +105,6 @@ private:
|
||||
Sampling(const GrSurfaceProxy& proxy,
|
||||
GrSamplerState sampler,
|
||||
const SkRect&,
|
||||
bool,
|
||||
const SkRect*,
|
||||
const GrCaps&);
|
||||
inline bool usesDecal() const;
|
||||
|
@ -70,10 +70,6 @@ std::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::Make(const sk_sp<GrTextur
|
||||
GrSurfaceProxyView view(proxies[i], origin, swizzle);
|
||||
if (domain) {
|
||||
SkASSERT(planeFilter != GrSamplerState::Filter::kMipMap);
|
||||
if (planeFilter != GrSamplerState::Filter::kNearest) {
|
||||
// Inset by half a pixel for bilerp, after scaling to the size of the plane
|
||||
planeDomain.inset(0.5f, 0.5f);
|
||||
}
|
||||
planeFPs[i] = GrTextureEffect::MakeSubset(std::move(view), kUnknown_SkAlphaType,
|
||||
*planeMatrix, planeFilter, planeDomain, caps);
|
||||
} else {
|
||||
|
@ -1071,17 +1071,14 @@ std::unique_ptr<GrDrawOp> GrTextureOp::Make(GrRecordingContext* context,
|
||||
|
||||
std::unique_ptr<GrFragmentProcessor> fp;
|
||||
if (domain) {
|
||||
// Update domain to match what GrTextureOp would do for bilerp, but don't do any
|
||||
// normalization since GrTextureEffect handles that and the origin.
|
||||
SkRect correctedDomain = normalize_domain(filter, {1.f, 1.f, 0.f}, domain);
|
||||
const auto& caps = *context->priv().caps();
|
||||
SkRect localRect;
|
||||
if (localQuad.asRect(&localRect)) {
|
||||
fp = GrTextureEffect::MakeSubset(std::move(proxyView), alphaType, SkMatrix::I(),
|
||||
filter, correctedDomain, localRect, caps);
|
||||
fp = GrTextureEffect::MakeSubset(std::move(proxyView), alphaType, SkMatrix::I(), filter,
|
||||
*domain, localRect, caps);
|
||||
} else {
|
||||
fp = GrTextureEffect::MakeSubset(std::move(proxyView), alphaType, SkMatrix::I(),
|
||||
filter, correctedDomain, caps);
|
||||
fp = GrTextureEffect::MakeSubset(std::move(proxyView), alphaType, SkMatrix::I(), filter,
|
||||
*domain, caps);
|
||||
}
|
||||
} else {
|
||||
fp = GrTextureEffect::Make(std::move(proxyView), alphaType, SkMatrix::I(), filter);
|
||||
|
Loading…
Reference in New Issue
Block a user