Clamp in GrBicubicEffect (to match SW and for general sanity)
Bug: skia:8809
Change-Id: I9f5b6428113602929b3a1b45c25b623e8da0e264
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/200512
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/GrTextureProducer.cpp b/src/gpu/GrTextureProducer.cpp
index a5affe9..6587174 100644
--- a/src/gpu/GrTextureProducer.cpp
+++ b/src/gpu/GrTextureProducer.cpp
@@ -229,11 +229,12 @@
GrTextureDomain::Mode wrapMode = fDomainNeedsDecal ? GrTextureDomain::kDecal_Mode
: GrTextureDomain::kClamp_Mode;
return GrBicubicEffect::Make(std::move(proxy), textureMatrix, kClampClamp,
- wrapMode, wrapMode,
+ wrapMode, wrapMode, this->alphaType(),
kDomain_DomainMode == domainMode ? &domain : nullptr);
} else {
return GrBicubicEffect::Make(std::move(proxy), textureMatrix,
- fDomainNeedsDecal ? kDecalDecal : kClampClamp);
+ fDomainNeedsDecal ? kDecalDecal : kClampClamp,
+ this->alphaType());
}
}
}
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index eb8b84a..0e0efb4 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -981,7 +981,7 @@
domain.fTop = domain.fBottom = srcRect.centerY();
}
if (bicubic) {
- fp = GrBicubicEffect::Make(std::move(proxy), texMatrix, domain);
+ fp = GrBicubicEffect::Make(std::move(proxy), texMatrix, domain, bitmap.alphaType());
} else {
fp = GrTextureDomainEffect::Make(std::move(proxy), texMatrix, domain,
GrTextureDomain::kClamp_Mode, samplerState.filter());
@@ -989,7 +989,7 @@
} else if (bicubic) {
SkASSERT(GrSamplerState::Filter::kNearest == samplerState.filter());
GrSamplerState::WrapMode wrapMode[2] = {samplerState.wrapModeX(), samplerState.wrapModeY()};
- fp = GrBicubicEffect::Make(std::move(proxy), texMatrix, wrapMode);
+ fp = GrBicubicEffect::Make(std::move(proxy), texMatrix, wrapMode, bitmap.alphaType());
} else {
fp = GrSimpleTextureEffect::Make(std::move(proxy), texMatrix, samplerState);
}
diff --git a/src/gpu/effects/GrBicubicEffect.cpp b/src/gpu/effects/GrBicubicEffect.cpp
index 8de347c..d804021 100644
--- a/src/gpu/effects/GrBicubicEffect.cpp
+++ b/src/gpu/effects/GrBicubicEffect.cpp
@@ -20,6 +20,7 @@
GrProcessorKeyBuilder* b) {
const GrBicubicEffect& bicubicEffect = effect.cast<GrBicubicEffect>();
b->add32(GrTextureDomain::GLDomain::DomainKey(bicubicEffect.domain()));
+ b->add32(bicubicEffect.alphaType());
}
protected:
@@ -98,9 +99,17 @@
"half4 s%d = wx.x * rowColors[0] + wx.y * rowColors[1] + wx.z * rowColors[2] + wx.w * rowColors[3];",
y);
}
- SkString bicubicColor("(wy.x * s0 + wy.y * s1 + wy.z * s2 + wy.w * s3)");
- fragBuilder->codeAppendf("%s = %s * %s;", args.fOutputColor, bicubicColor.c_str(),
- args.fInputColor);
+ fragBuilder->codeAppend("half4 bicubicColor = wy.x * s0 + wy.y * s1 + wy.z * s2 + wy.w * s3;");
+ // Bicubic can send colors out of range, so clamp to get them back in (source) gamut.
+ // The kind of clamp we have to do depends on the alpha type.
+ if (kPremul_SkAlphaType == bicubicEffect.alphaType()) {
+ fragBuilder->codeAppend("bicubicColor.a = saturate(bicubicColor.a);");
+ fragBuilder->codeAppend(
+ "bicubicColor.rgb = max(half3(0.0), min(bicubicColor.rgb, bicubicColor.aaa));");
+ } else {
+ fragBuilder->codeAppend("bicubicColor = saturate(bicubicColor);");
+ }
+ fragBuilder->codeAppendf("%s = bicubicColor * %s;", args.fOutputColor, args.fInputColor);
}
void GrGLBicubicEffect::onSetData(const GrGLSLProgramDataManager& pdman,
@@ -120,14 +129,16 @@
GrBicubicEffect::GrBicubicEffect(sk_sp<GrTextureProxy> proxy,
const SkMatrix& matrix, const SkRect& domain,
const GrSamplerState::WrapMode wrapModes[2],
- GrTextureDomain::Mode modeX, GrTextureDomain::Mode modeY)
+ GrTextureDomain::Mode modeX, GrTextureDomain::Mode modeY,
+ SkAlphaType alphaType)
: INHERITED{kGrBicubicEffect_ClassID,
ModulateForSamplerOptFlags(proxy->config(),
GrTextureDomain::IsDecalSampled(wrapModes, modeX,modeY))}
, fCoordTransform(matrix, proxy.get())
, fDomain(proxy.get(), domain, modeX, modeY)
, fTextureSampler(std::move(proxy),
- GrSamplerState(wrapModes, GrSamplerState::Filter::kNearest)) {
+ GrSamplerState(wrapModes, GrSamplerState::Filter::kNearest))
+ , fAlphaType(alphaType) {
this->addCoordTransform(&fCoordTransform);
this->setTextureSamplerCnt(1);
}
@@ -136,7 +147,8 @@
: INHERITED(kGrBicubicEffect_ClassID, that.optimizationFlags())
, fCoordTransform(that.fCoordTransform)
, fDomain(that.fDomain)
- , fTextureSampler(that.fTextureSampler) {
+ , fTextureSampler(that.fTextureSampler)
+ , fAlphaType(that.fAlphaType) {
this->addCoordTransform(&fCoordTransform);
this->setTextureSamplerCnt(1);
}
@@ -163,7 +175,8 @@
: GrProcessorUnitTest::kAlphaTextureIdx;
static const GrSamplerState::WrapMode kClampClamp[] = {GrSamplerState::WrapMode::kClamp,
GrSamplerState::WrapMode::kClamp};
- return GrBicubicEffect::Make(d->textureProxy(texIdx), SkMatrix::I(), kClampClamp);
+ SkAlphaType alphaType = d->fRandom->nextBool() ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
+ return GrBicubicEffect::Make(d->textureProxy(texIdx), SkMatrix::I(), kClampClamp, alphaType);
}
#endif
diff --git a/src/gpu/effects/GrBicubicEffect.h b/src/gpu/effects/GrBicubicEffect.h
index be2e44c..9086b5a 100644
--- a/src/gpu/effects/GrBicubicEffect.h
+++ b/src/gpu/effects/GrBicubicEffect.h
@@ -28,16 +28,19 @@
const GrTextureDomain& domain() const { return fDomain; }
+ SkAlphaType alphaType() const { return fAlphaType; }
+
/**
* Create a Mitchell filter effect with specified texture matrix and x/y tile modes.
*/
static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> proxy,
const SkMatrix& matrix,
- const GrSamplerState::WrapMode wrapModes[2]) {
+ const GrSamplerState::WrapMode wrapModes[2],
+ SkAlphaType alphaType) {
// Ignore the domain on x and y, since this factory relies solely on the wrap mode of the
// sampler to constrain texture coordinates
return Make(std::move(proxy), matrix, wrapModes, GrTextureDomain::kIgnore_Mode,
- GrTextureDomain::kIgnore_Mode);
+ GrTextureDomain::kIgnore_Mode, alphaType);
}
/**
@@ -50,11 +53,12 @@
const GrSamplerState::WrapMode wrapModes[2],
GrTextureDomain::Mode modeX,
GrTextureDomain::Mode modeY,
+ SkAlphaType alphaType,
const SkRect* domain = nullptr) {
SkRect resolvedDomain = domain ? *domain : GrTextureDomain::MakeTexelDomain(
SkIRect::MakeWH(proxy->width(), proxy->height()), modeX, modeY);
return std::unique_ptr<GrFragmentProcessor>(new GrBicubicEffect(
- std::move(proxy), matrix, resolvedDomain, wrapModes, modeX, modeY));
+ std::move(proxy), matrix, resolvedDomain, wrapModes, modeX, modeY, alphaType));
}
/**
@@ -62,11 +66,12 @@
*/
static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> proxy,
const SkMatrix& matrix,
- const SkRect& domain) {
+ const SkRect& domain,
+ SkAlphaType alphaType) {
static const GrSamplerState::WrapMode kClampClamp[] = {
GrSamplerState::WrapMode::kClamp, GrSamplerState::WrapMode::kClamp};
return Make(std::move(proxy), matrix, kClampClamp, GrTextureDomain::kClamp_Mode,
- GrTextureDomain::kClamp_Mode, &domain);
+ GrTextureDomain::kClamp_Mode, alphaType, &domain);
}
/**
@@ -82,7 +87,8 @@
private:
GrBicubicEffect(sk_sp<GrTextureProxy>, const SkMatrix& matrix, const SkRect& domain,
const GrSamplerState::WrapMode wrapModes[2],
- GrTextureDomain::Mode modeX, GrTextureDomain::Mode modeY);
+ GrTextureDomain::Mode modeX, GrTextureDomain::Mode modeY,
+ SkAlphaType alphaType);
explicit GrBicubicEffect(const GrBicubicEffect&);
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
@@ -96,6 +102,7 @@
GrCoordTransform fCoordTransform;
GrTextureDomain fDomain;
TextureSampler fTextureSampler;
+ SkAlphaType fAlphaType;
GR_DECLARE_FRAGMENT_PROCESSOR_TEST
diff --git a/src/shaders/SkImageShader.cpp b/src/shaders/SkImageShader.cpp
index 2195019..2065b7b 100644
--- a/src/shaders/SkImageShader.cpp
+++ b/src/shaders/SkImageShader.cpp
@@ -237,7 +237,8 @@
if (doBicubic) {
// domainX and domainY will properly apply the decal effect with the texture domain used in
// the bicubic filter if clamp to border was unsupported in hardware
- inner = GrBicubicEffect::Make(std::move(proxy), lmInverse, wrapModes, domainX, domainY);
+ inner = GrBicubicEffect::Make(std::move(proxy), lmInverse, wrapModes, domainX, domainY,
+ fImage->alphaType());
} else {
if (domainX != GrTextureDomain::kIgnore_Mode || domainY != GrTextureDomain::kIgnore_Mode) {
SkRect domain = GrTextureDomain::MakeTexelDomain(