Decal fallback for SkImageShader
Bug: skia: Change-Id: Ib39f74886c0edc655ded8ba1075e5205361ae650 Reviewed-on: https://skia-review.googlesource.com/c/176225 Commit-Queue: Michael Ludwig <michaelludwig@google.com> Reviewed-by: Greg Daniel <egdaniel@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com>
This commit is contained in:
parent
1be2d421ce
commit
be315a2748
@ -15,6 +15,7 @@
|
||||
#include "GrRenderTargetContextPriv.h"
|
||||
#include "SkGradientShader.h"
|
||||
#include "SkImage.h"
|
||||
#include "SkImage_Base.h"
|
||||
#include "SkSurface.h"
|
||||
#include "effects/GrTextureDomain.h"
|
||||
#include "ops/GrDrawOp.h"
|
||||
@ -26,13 +27,20 @@ namespace skiagm {
|
||||
*/
|
||||
class TextureDomainEffect : public GM {
|
||||
public:
|
||||
TextureDomainEffect() {
|
||||
TextureDomainEffect(GrSamplerState::Filter filter)
|
||||
: fFilter(filter) {
|
||||
this->setBGColor(0xFFFFFFFF);
|
||||
}
|
||||
|
||||
protected:
|
||||
SkString onShortName() override {
|
||||
return SkString("texture_domain_effect");
|
||||
SkString name("texture_domain_effect");
|
||||
if (fFilter == GrSamplerState::Filter::kBilerp) {
|
||||
name.append("_bilerp");
|
||||
} else if (fFilter == GrSamplerState::Filter::kMipMap) {
|
||||
name.append("_mipmap");
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
SkISize onISize() override {
|
||||
@ -88,8 +96,18 @@ protected:
|
||||
}
|
||||
|
||||
GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
|
||||
sk_sp<GrTextureProxy> proxy = proxyProvider->createTextureProxy(
|
||||
sk_sp<GrTextureProxy> proxy;
|
||||
if (fFilter == GrSamplerState::Filter::kMipMap) {
|
||||
SkBitmap copy;
|
||||
SkImageInfo info = as_IB(fImage)->onImageInfo().makeColorType(kN32_SkColorType);
|
||||
if (!copy.tryAllocPixels(info) || !fImage->readPixels(copy.pixmap(), 0, 0)) {
|
||||
return;
|
||||
}
|
||||
proxy = proxyProvider->createMipMapProxyFromBitmap(copy);
|
||||
} else {
|
||||
proxy = proxyProvider->createTextureProxy(
|
||||
fImage, kNone_GrSurfaceFlags, 1, SkBudgeted::kYes, SkBackingFit::kExact);
|
||||
}
|
||||
if (!proxy) {
|
||||
return;
|
||||
}
|
||||
@ -100,11 +118,10 @@ protected:
|
||||
textureMatrices.push_back();
|
||||
textureMatrices.back().setRotate(45.f, proxy->width() / 2.f, proxy->height() / 2.f);
|
||||
|
||||
|
||||
const SkIRect texelDomains[] = {
|
||||
fImage->bounds(),
|
||||
SkIRect::MakeXYWH(fImage->width() / 4, fImage->height() / 4,
|
||||
fImage->width() / 2, fImage->height() / 2),
|
||||
SkIRect::MakeXYWH(fImage->width() / 4 - 1, fImage->height() / 4 - 1,
|
||||
fImage->width() / 2 + 2, fImage->height() / 2 + 2),
|
||||
};
|
||||
|
||||
SkRect renderRect = SkRect::Make(fImage->bounds());
|
||||
@ -116,12 +133,18 @@ protected:
|
||||
SkScalar x = kDrawPad + kTestPad;
|
||||
for (int m = 0; m < GrTextureDomain::kModeCount; ++m) {
|
||||
GrTextureDomain::Mode mode = (GrTextureDomain::Mode) m;
|
||||
if (fFilter != GrSamplerState::Filter::kNearest &&
|
||||
mode == GrTextureDomain::kRepeat_Mode) {
|
||||
// Repeat mode doesn't produce correct results with bilerp filtering
|
||||
continue;
|
||||
}
|
||||
|
||||
GrPaint grPaint;
|
||||
grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
|
||||
auto fp = GrTextureDomainEffect::Make(
|
||||
proxy, textureMatrices[tm],
|
||||
GrTextureDomain::MakeTexelDomainForMode(texelDomains[d], mode), mode,
|
||||
GrSamplerState::Filter::kNearest);
|
||||
GrTextureDomain::MakeTexelDomain(texelDomains[d], mode),
|
||||
mode, fFilter);
|
||||
|
||||
if (!fp) {
|
||||
continue;
|
||||
@ -144,9 +167,13 @@ private:
|
||||
static constexpr int kTargetWidth = 100;
|
||||
static constexpr int kTargetHeight = 100;
|
||||
sk_sp<SkImage> fImage;
|
||||
GrSamplerState::Filter fFilter;
|
||||
|
||||
typedef GM INHERITED;
|
||||
};
|
||||
|
||||
DEF_GM(return new TextureDomainEffect;)
|
||||
DEF_GM(return new TextureDomainEffect(GrSamplerState::Filter::kNearest);)
|
||||
DEF_GM(return new TextureDomainEffect(GrSamplerState::Filter::kBilerp);)
|
||||
DEF_GM(return new TextureDomainEffect(GrSamplerState::Filter::kMipMap);)
|
||||
|
||||
}
|
||||
|
@ -265,17 +265,29 @@ DEF_GM( return new Tiling2GM(make_grad, "gradient"); )
|
||||
|
||||
#include "SkGradientShader.h"
|
||||
|
||||
DEF_SIMPLE_GM(tilemode_decal, canvas, 715, 560) {
|
||||
DEF_SIMPLE_GM(tilemode_decal, canvas, 720, 1100) {
|
||||
auto img = GetResourceAsImage("images/mandrill_128.png");
|
||||
SkPaint bgpaint;
|
||||
bgpaint.setColor(SK_ColorYELLOW);
|
||||
|
||||
SkRect r = { -20, -20, img->width() + 20.0f, img->height() + 20.0f };
|
||||
canvas->translate(25, 25);
|
||||
canvas->translate(45, 45);
|
||||
|
||||
std::function<void(SkPaint*, SkShader::TileMode, SkShader::TileMode)> shader_procs[] = {
|
||||
[img](SkPaint* paint, SkShader::TileMode tx, SkShader::TileMode ty) {
|
||||
// Test no filtering with decal mode
|
||||
paint->setShader(img->makeShader(tx, ty));
|
||||
paint->setFilterQuality(kNone_SkFilterQuality);
|
||||
},
|
||||
[img](SkPaint* paint, SkShader::TileMode tx, SkShader::TileMode ty) {
|
||||
// Test bilerp approximation for decal mode (or clamp to border HW)
|
||||
paint->setShader(img->makeShader(tx, ty));
|
||||
paint->setFilterQuality(kLow_SkFilterQuality);
|
||||
},
|
||||
[img](SkPaint* paint, SkShader::TileMode tx, SkShader::TileMode ty) {
|
||||
// Test bicubic filter with decal mode
|
||||
paint->setShader(img->makeShader(tx, ty));
|
||||
paint->setFilterQuality(kHigh_SkFilterQuality);
|
||||
},
|
||||
[img](SkPaint* paint, SkShader::TileMode tx, SkShader::TileMode ty) {
|
||||
SkColor colors[] = { SK_ColorRED, SK_ColorBLUE };
|
||||
@ -306,9 +318,14 @@ DEF_SIMPLE_GM(tilemode_decal, canvas, 715, 560) {
|
||||
SkPaint paint;
|
||||
canvas->save();
|
||||
for (const auto& proc : shader_procs) {
|
||||
canvas->save();
|
||||
// Apply a slight rotation to highlight the differences between filtered and unfiltered
|
||||
// decal edges
|
||||
canvas->rotate(4);
|
||||
canvas->drawRect(r, bgpaint);
|
||||
proc(&paint, p.fX, p.fY);
|
||||
canvas->drawRect(r, paint);
|
||||
canvas->restore();
|
||||
canvas->translate(0, r.height() + 20);
|
||||
}
|
||||
canvas->restore();
|
||||
|
@ -314,7 +314,7 @@ sk_sp<SkSpecialImage> ArithmeticImageFilterImpl::filterImageGPU(
|
||||
SkIntToScalar(bgSubset.top() - backgroundOffset.fY));
|
||||
bgFP = GrTextureDomainEffect::Make(
|
||||
std::move(backgroundProxy), backgroundMatrix,
|
||||
GrTextureDomain::MakeTexelDomain(bgSubset),
|
||||
GrTextureDomain::MakeTexelDomain(bgSubset, GrTextureDomain::kDecal_Mode),
|
||||
GrTextureDomain::kDecal_Mode, GrSamplerState::Filter::kNearest);
|
||||
bgFP = GrColorSpaceXformEffect::Make(std::move(bgFP), background->getColorSpace(),
|
||||
background->alphaType(),
|
||||
@ -331,7 +331,7 @@ sk_sp<SkSpecialImage> ArithmeticImageFilterImpl::filterImageGPU(
|
||||
SkIntToScalar(fgSubset.top() - foregroundOffset.fY));
|
||||
auto foregroundFP = GrTextureDomainEffect::Make(
|
||||
std::move(foregroundProxy), foregroundMatrix,
|
||||
GrTextureDomain::MakeTexelDomain(fgSubset),
|
||||
GrTextureDomain::MakeTexelDomain(fgSubset, GrTextureDomain::kDecal_Mode),
|
||||
GrTextureDomain::kDecal_Mode, GrSamplerState::Filter::kNearest);
|
||||
foregroundFP = GrColorSpaceXformEffect::Make(std::move(foregroundFP),
|
||||
foreground->getColorSpace(),
|
||||
|
@ -448,8 +448,10 @@ GrDisplacementMapEffect::GrDisplacementMapEffect(
|
||||
, fDisplacementTransform(offsetMatrix, displacement.get())
|
||||
, fDisplacementSampler(displacement)
|
||||
, fColorTransform(color.get())
|
||||
, fDomain(color.get(), GrTextureDomain::MakeTexelDomain(SkIRect::MakeSize(colorDimensions)),
|
||||
GrTextureDomain::kDecal_Mode)
|
||||
, fDomain(color.get(),
|
||||
GrTextureDomain::MakeTexelDomain(SkIRect::MakeSize(colorDimensions),
|
||||
GrTextureDomain::kDecal_Mode),
|
||||
GrTextureDomain::kDecal_Mode, GrTextureDomain::kDecal_Mode)
|
||||
, fColorSampler(color)
|
||||
, fXChannelSelector(xChannelSelector)
|
||||
, fYChannelSelector(yChannelSelector)
|
||||
@ -605,7 +607,8 @@ void GrGLDisplacementMapEffect::onSetData(const GrGLSLProgramDataManager& pdman,
|
||||
pdman.set2f(fScaleUni, SkScalarToFloat(scaleX),
|
||||
proxy->origin() == kTopLeft_GrSurfaceOrigin ?
|
||||
SkScalarToFloat(scaleY) : SkScalarToFloat(-scaleY));
|
||||
fGLDomain.setData(pdman, displacementMap.domain(), proxy);
|
||||
fGLDomain.setData(pdman, displacementMap.domain(), proxy,
|
||||
displacementMap.textureSampler(1).samplerState());
|
||||
}
|
||||
|
||||
void GrGLDisplacementMapEffect::GenKey(const GrProcessor& proc,
|
||||
|
@ -1676,8 +1676,8 @@ private:
|
||||
static GrTextureDomain create_domain(GrTextureProxy* proxy, const SkIRect* srcBounds,
|
||||
GrTextureDomain::Mode mode) {
|
||||
if (srcBounds) {
|
||||
SkRect texelDomain = GrTextureDomain::MakeTexelDomainForMode(*srcBounds, mode);
|
||||
return GrTextureDomain(proxy, texelDomain, mode);
|
||||
SkRect texelDomain = GrTextureDomain::MakeTexelDomain(*srcBounds, mode);
|
||||
return GrTextureDomain(proxy, texelDomain, mode, mode);
|
||||
} else {
|
||||
return GrTextureDomain::IgnoredDomain();
|
||||
}
|
||||
@ -1926,7 +1926,7 @@ void GrGLLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman,
|
||||
pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
|
||||
sk_sp<SkImageFilterLight> transformedLight(
|
||||
lighting.light()->transform(lighting.filterMatrix()));
|
||||
fDomain.setData(pdman, lighting.domain(), proxy);
|
||||
fDomain.setData(pdman, lighting.domain(), proxy, lighting.textureSampler(0).samplerState());
|
||||
fLight->setData(pdman, transformedLight.get());
|
||||
}
|
||||
|
||||
|
@ -280,10 +280,10 @@ sk_sp<SkSpecialImage> SkXfermodeImageFilter_Base::filterImageGPU(
|
||||
SkMatrix bgMatrix = SkMatrix::MakeTrans(
|
||||
SkIntToScalar(bgSubset.left() - backgroundOffset.fX),
|
||||
SkIntToScalar(bgSubset.top() - backgroundOffset.fY));
|
||||
bgFP = GrTextureDomainEffect::Make(std::move(backgroundProxy), bgMatrix,
|
||||
GrTextureDomain::MakeTexelDomain(bgSubset),
|
||||
GrTextureDomain::kDecal_Mode,
|
||||
GrSamplerState::Filter::kNearest);
|
||||
bgFP = GrTextureDomainEffect::Make(
|
||||
std::move(backgroundProxy), bgMatrix,
|
||||
GrTextureDomain::MakeTexelDomain(bgSubset, GrTextureDomain::kDecal_Mode),
|
||||
GrTextureDomain::kDecal_Mode, GrSamplerState::Filter::kNearest);
|
||||
bgFP = GrColorSpaceXformEffect::Make(std::move(bgFP), background->getColorSpace(),
|
||||
background->alphaType(),
|
||||
outputProperties.colorSpace());
|
||||
@ -299,7 +299,7 @@ sk_sp<SkSpecialImage> SkXfermodeImageFilter_Base::filterImageGPU(
|
||||
SkIntToScalar(fgSubset.top() - foregroundOffset.fY));
|
||||
auto foregroundFP = GrTextureDomainEffect::Make(
|
||||
std::move(foregroundProxy), fgMatrix,
|
||||
GrTextureDomain::MakeTexelDomain(fgSubset),
|
||||
GrTextureDomain::MakeTexelDomain(fgSubset, GrTextureDomain::kDecal_Mode),
|
||||
GrTextureDomain::kDecal_Mode, GrSamplerState::Filter::kNearest);
|
||||
foregroundFP = GrColorSpaceXformEffect::Make(std::move(foregroundFP),
|
||||
foreground->getColorSpace(),
|
||||
|
@ -113,15 +113,20 @@ void GrGLBicubicEffect::onSetData(const GrGLSLProgramDataManager& pdman,
|
||||
imageIncrement[0] = 1.0f / texture->width();
|
||||
imageIncrement[1] = 1.0f / texture->height();
|
||||
pdman.set2fv(fImageIncrementUni, 1, imageIncrement);
|
||||
fDomain.setData(pdman, bicubicEffect.domain(), proxy);
|
||||
fDomain.setData(pdman, bicubicEffect.domain(), proxy,
|
||||
processor.textureSampler(0).samplerState());
|
||||
}
|
||||
|
||||
GrBicubicEffect::GrBicubicEffect(sk_sp<GrTextureProxy> proxy,
|
||||
const SkMatrix& matrix,
|
||||
const GrSamplerState::WrapMode wrapModes[2])
|
||||
const GrSamplerState::WrapMode wrapModes[2],
|
||||
GrTextureDomain::Mode modeX, GrTextureDomain::Mode modeY)
|
||||
: INHERITED{kGrBicubicEffect_ClassID, ModulateByConfigOptimizationFlags(proxy->config())}
|
||||
, fCoordTransform(matrix, proxy.get())
|
||||
, fDomain(GrTextureDomain::IgnoredDomain())
|
||||
, fDomain(proxy.get(),
|
||||
GrTextureDomain::MakeTexelDomain(
|
||||
SkIRect::MakeWH(proxy->width(), proxy->height()), modeX, modeY),
|
||||
modeX, modeY)
|
||||
, fTextureSampler(std::move(proxy),
|
||||
GrSamplerState(wrapModes, GrSamplerState::Filter::kNearest)) {
|
||||
this->addCoordTransform(&fCoordTransform);
|
||||
@ -133,7 +138,7 @@ GrBicubicEffect::GrBicubicEffect(sk_sp<GrTextureProxy> proxy,
|
||||
const SkRect& domain)
|
||||
: INHERITED(kGrBicubicEffect_ClassID, ModulateByConfigOptimizationFlags(proxy->config()))
|
||||
, fCoordTransform(matrix, proxy.get())
|
||||
, fDomain(proxy.get(), domain, GrTextureDomain::kClamp_Mode)
|
||||
, fDomain(proxy.get(), domain, GrTextureDomain::kClamp_Mode, GrTextureDomain::kClamp_Mode)
|
||||
, fTextureSampler(std::move(proxy)) {
|
||||
this->addCoordTransform(&fCoordTransform);
|
||||
this->setTextureSamplerCnt(1);
|
||||
|
@ -34,8 +34,24 @@ public:
|
||||
static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> proxy,
|
||||
const SkMatrix& matrix,
|
||||
const GrSamplerState::WrapMode wrapModes[2]) {
|
||||
// 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Mitchell filter effect with specified texture matrix and x/y tile modes. This
|
||||
* supports providing modes for the texture domain explicitly, in the event that it should
|
||||
* override the behavior of the sampler's tile mode (e.g. clamp to border unsupported).
|
||||
*/
|
||||
static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> proxy,
|
||||
const SkMatrix& matrix,
|
||||
const GrSamplerState::WrapMode wrapModes[2],
|
||||
GrTextureDomain::Mode modeX,
|
||||
GrTextureDomain::Mode modeY) {
|
||||
return std::unique_ptr<GrFragmentProcessor>(new GrBicubicEffect(std::move(proxy), matrix,
|
||||
wrapModes));
|
||||
wrapModes, modeX, modeY));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -60,7 +76,8 @@ public:
|
||||
|
||||
private:
|
||||
GrBicubicEffect(sk_sp<GrTextureProxy>, const SkMatrix& matrix,
|
||||
const GrSamplerState::WrapMode wrapModes[2]);
|
||||
const GrSamplerState::WrapMode wrapModes[2],
|
||||
GrTextureDomain::Mode modeX, GrTextureDomain::Mode modeY);
|
||||
GrBicubicEffect(sk_sp<GrTextureProxy>, const SkMatrix &matrix, const SkRect& domain);
|
||||
explicit GrBicubicEffect(const GrBicubicEffect&);
|
||||
|
||||
|
@ -140,7 +140,7 @@ void GrGLMatrixConvolutionEffect::onSetData(const GrGLSLProgramDataManager& pdma
|
||||
pdman.set4fv(fKernelUni, arrayCount, conv.kernel());
|
||||
pdman.set1f(fGainUni, conv.gain());
|
||||
pdman.set1f(fBiasUni, conv.bias());
|
||||
fDomain.setData(pdman, conv.domain(), proxy);
|
||||
fDomain.setData(pdman, conv.domain(), proxy, conv.textureSampler(0).samplerState());
|
||||
}
|
||||
|
||||
GrMatrixConvolutionEffect::GrMatrixConvolutionEffect(sk_sp<GrTextureProxy> srcProxy,
|
||||
@ -156,9 +156,8 @@ GrMatrixConvolutionEffect::GrMatrixConvolutionEffect(sk_sp<GrTextureProxy> srcPr
|
||||
// parameters.
|
||||
: INHERITED(kGrMatrixConvolutionEffect_ClassID, kNone_OptimizationFlags)
|
||||
, fCoordTransform(srcProxy.get())
|
||||
, fDomain(srcProxy.get(),
|
||||
GrTextureDomain::MakeTexelDomainForMode(srcBounds, tileMode),
|
||||
tileMode)
|
||||
, fDomain(srcProxy.get(), GrTextureDomain::MakeTexelDomain(srcBounds, tileMode),
|
||||
tileMode, tileMode)
|
||||
, fTextureSampler(std::move(srcProxy))
|
||||
, fKernelSize(kernelSize)
|
||||
, fGain(SkScalarToFloat(gain))
|
||||
|
@ -21,26 +21,14 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
static bool can_ignore_rect(GrTextureProxy* proxy, const SkRect& domain) {
|
||||
if (GrProxyProvider::IsFunctionallyExact(proxy)) {
|
||||
const SkIRect kFullRect = SkIRect::MakeWH(proxy->width(), proxy->height());
|
||||
|
||||
return domain.contains(kFullRect);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
GrTextureDomain::GrTextureDomain(GrTextureProxy* proxy, const SkRect& domain, Mode mode, int index)
|
||||
: fMode(mode)
|
||||
GrTextureDomain::GrTextureDomain(GrTextureProxy* proxy, const SkRect& domain, Mode modeX,
|
||||
Mode modeY, int index)
|
||||
: fModeX(modeX)
|
||||
, fModeY(modeY)
|
||||
, fIndex(index) {
|
||||
|
||||
if (kIgnore_Mode == fMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (kClamp_Mode == mode && can_ignore_rect(proxy, domain)) {
|
||||
fMode = kIgnore_Mode;
|
||||
if (!proxy) {
|
||||
SkASSERT(modeX == kIgnore_Mode && modeY == kIgnore_Mode);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -61,6 +49,33 @@ GrTextureDomain::GrTextureDomain(GrTextureProxy* proxy, const SkRect& domain, Mo
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static SkString clamp_expression(GrTextureDomain::Mode mode, const char* inCoord,
|
||||
const char* coordSwizzle, const char* domain,
|
||||
const char* minSwizzle, const char* maxSwizzle) {
|
||||
SkString clampedExpr;
|
||||
switch(mode) {
|
||||
case GrTextureDomain::kIgnore_Mode:
|
||||
clampedExpr.printf("%s.%s\n", inCoord, coordSwizzle);
|
||||
break;
|
||||
case GrTextureDomain::kDecal_Mode:
|
||||
// The lookup coordinate to use for decal will be clamped just like kClamp_Mode,
|
||||
// it's just that the post-processing will be different, so fall through
|
||||
case GrTextureDomain::kClamp_Mode:
|
||||
clampedExpr.printf("clamp(%s.%s, %s.%s, %s.%s)",
|
||||
inCoord, coordSwizzle, domain, minSwizzle, domain, maxSwizzle);
|
||||
break;
|
||||
case GrTextureDomain::kRepeat_Mode:
|
||||
clampedExpr.printf("mod(%s.%s - %s.%s, %s.%s - %s.%s) + %s.%s",
|
||||
inCoord, coordSwizzle, domain, minSwizzle, domain, maxSwizzle,
|
||||
domain, minSwizzle, domain, minSwizzle);
|
||||
break;
|
||||
default:
|
||||
SkASSERTF(false, "Unknown texture domain mode: %u\n", (uint32_t) mode);
|
||||
break;
|
||||
}
|
||||
return clampedExpr;
|
||||
}
|
||||
|
||||
void GrTextureDomain::GLDomain::sampleTexture(GrGLSLShaderBuilder* builder,
|
||||
GrGLSLUniformHandler* uniformHandler,
|
||||
const GrShaderCaps* shaderCaps,
|
||||
@ -69,11 +84,14 @@ void GrTextureDomain::GLDomain::sampleTexture(GrGLSLShaderBuilder* builder,
|
||||
const SkString& inCoords,
|
||||
GrGLSLFragmentProcessor::SamplerHandle sampler,
|
||||
const char* inModulateColor) {
|
||||
SkASSERT(!fHasMode || textureDomain.mode() == fMode);
|
||||
SkDEBUGCODE(fMode = textureDomain.mode();)
|
||||
SkASSERT(!fHasMode || (textureDomain.modeX() == fModeX && textureDomain.modeY() == fModeY));
|
||||
SkDEBUGCODE(fModeX = textureDomain.modeX();)
|
||||
SkDEBUGCODE(fModeY = textureDomain.modeY();)
|
||||
SkDEBUGCODE(fHasMode = true;)
|
||||
|
||||
if (textureDomain.mode() != kIgnore_Mode && !fDomainUni.isValid()) {
|
||||
if ((textureDomain.modeX() != kIgnore_Mode || textureDomain.modeY() != kIgnore_Mode) &&
|
||||
!fDomainUni.isValid()) {
|
||||
// Must include the domain uniform since at least one axis uses it
|
||||
const char* name;
|
||||
SkString uniName("TexDom");
|
||||
if (textureDomain.fIndex >= 0) {
|
||||
@ -84,95 +102,114 @@ void GrTextureDomain::GLDomain::sampleTexture(GrGLSLShaderBuilder* builder,
|
||||
fDomainName = name;
|
||||
}
|
||||
|
||||
switch (textureDomain.mode()) {
|
||||
case kIgnore_Mode: {
|
||||
builder->codeAppendf("%s = ", outColor);
|
||||
builder->appendTextureLookupAndModulate(inModulateColor, sampler, inCoords.c_str(),
|
||||
kFloat2_GrSLType);
|
||||
builder->codeAppend(";");
|
||||
break;
|
||||
bool decalX = textureDomain.modeX() == kDecal_Mode;
|
||||
bool decalY = textureDomain.modeY() == kDecal_Mode;
|
||||
if ((decalX || decalY) && !fDecalUni.isValid()) {
|
||||
const char* name;
|
||||
SkString uniName("DecalParams");
|
||||
if (textureDomain.fIndex >= 0) {
|
||||
uniName.appendS32(textureDomain.fIndex);
|
||||
}
|
||||
// Half3 since this will hold texture width, height, and then a step function control param
|
||||
fDecalUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf3_GrSLType,
|
||||
uniName.c_str(), &name);
|
||||
fDecalName = name;
|
||||
}
|
||||
case kClamp_Mode: {
|
||||
SkString clampedCoords;
|
||||
clampedCoords.appendf("clamp(%s, %s.xy, %s.zw)",
|
||||
inCoords.c_str(), fDomainName.c_str(), fDomainName.c_str());
|
||||
|
||||
builder->codeAppendf("%s = ", outColor);
|
||||
builder->appendTextureLookupAndModulate(inModulateColor, sampler, clampedCoords.c_str(),
|
||||
kFloat2_GrSLType);
|
||||
builder->codeAppend(";");
|
||||
break;
|
||||
}
|
||||
case kDecal_Mode: {
|
||||
// Add a block since we're going to declare variables.
|
||||
// Add a block so that we can declare variables
|
||||
GrGLSLShaderBuilder::ShaderBlock block(builder);
|
||||
|
||||
const char* domain = fDomainName.c_str();
|
||||
if (!shaderCaps->canUseAnyFunctionInShader()) {
|
||||
// On the NexusS and GalaxyNexus, the other path (with the 'any'
|
||||
// call) causes the compilation error "Calls to any function that
|
||||
// may require a gradient calculation inside a conditional block
|
||||
// may return undefined results". This appears to be an issue with
|
||||
// the 'any' call since even the simple "result=black; if (any())
|
||||
// result=white;" code fails to compile.
|
||||
builder->codeAppend("half4 outside = half4(0.0, 0.0, 0.0, 0.0);");
|
||||
builder->codeAppend("half4 inside = ");
|
||||
builder->appendTextureLookupAndModulate(inModulateColor, sampler, inCoords.c_str(),
|
||||
kFloat2_GrSLType);
|
||||
builder->codeAppend(";");
|
||||
|
||||
builder->codeAppendf("float x = (%s).x;", inCoords.c_str());
|
||||
builder->codeAppendf("float y = (%s).y;", inCoords.c_str());
|
||||
|
||||
builder->codeAppendf("x = abs(2.0*(x - %s.x)/(%s.z - %s.x) - 1.0);",
|
||||
domain, domain, domain);
|
||||
builder->codeAppendf("y = abs(2.0*(y - %s.y)/(%s.w - %s.y) - 1.0);",
|
||||
domain, domain, domain);
|
||||
builder->codeAppend("half blend = step(1.0, max(x, y));");
|
||||
builder->codeAppendf("%s = mix(inside, outside, blend);", outColor);
|
||||
// Always use a local variable for the input coordinates; often callers pass in an expression
|
||||
// and we want to cache it across all of its references in the code below
|
||||
builder->codeAppendf("float2 origCoord = %s;", inCoords.c_str());
|
||||
builder->codeAppend("float2 clampedCoord = ");
|
||||
if (textureDomain.modeX() != textureDomain.modeY()) {
|
||||
// The wrap modes differ on the two axes, so build up a coordinate that respects each axis'
|
||||
// domain rule independently before sampling the texture.
|
||||
SkString tcX = clamp_expression(textureDomain.modeX(), "origCoord", "x",
|
||||
fDomainName.c_str(), "x", "z");
|
||||
SkString tcY = clamp_expression(textureDomain.modeY(), "origCoord", "y",
|
||||
fDomainName.c_str(), "y", "w");
|
||||
builder->codeAppendf("float2(%s, %s)", tcX.c_str(), tcY.c_str());
|
||||
} else {
|
||||
builder->codeAppend("bool4 outside;\n");
|
||||
builder->codeAppendf("outside.xy = lessThan(%s, %s.xy);", inCoords.c_str(),
|
||||
domain);
|
||||
builder->codeAppendf("outside.zw = greaterThan(%s, %s.zw);", inCoords.c_str(),
|
||||
domain);
|
||||
builder->codeAppendf("%s = any(outside) ? half4(0.0, 0.0, 0.0, 0.0) : ",
|
||||
outColor);
|
||||
builder->appendTextureLookupAndModulate(inModulateColor, sampler, inCoords.c_str(),
|
||||
kFloat2_GrSLType);
|
||||
// Since the x and y axis wrap modes are the same, they can be calculated together using
|
||||
// more efficient vector operations
|
||||
SkString tc = clamp_expression(textureDomain.modeX(), "origCoord", "xy",
|
||||
fDomainName.c_str(), "xy", "zw");
|
||||
builder->codeAppend(tc.c_str());
|
||||
}
|
||||
builder->codeAppend(";");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kRepeat_Mode: {
|
||||
SkString clampedCoords;
|
||||
clampedCoords.printf("mod(%s - %s.xy, %s.zw - %s.xy) + %s.xy",
|
||||
inCoords.c_str(), fDomainName.c_str(), fDomainName.c_str(),
|
||||
fDomainName.c_str(), fDomainName.c_str());
|
||||
|
||||
builder->codeAppendf("%s = ", outColor);
|
||||
builder->appendTextureLookupAndModulate(inModulateColor, sampler, clampedCoords.c_str(),
|
||||
// Look up the texture sample at the clamped coordinate location
|
||||
builder->codeAppend("half4 inside = ");
|
||||
builder->appendTextureLookupAndModulate(inModulateColor, sampler, "clampedCoord",
|
||||
kFloat2_GrSLType);
|
||||
builder->codeAppend(";");
|
||||
break;
|
||||
|
||||
// Apply decal mode's transparency interpolation if needed
|
||||
if (decalX || decalY) {
|
||||
// The decal err is the max absoluate value between the clamped coordinate and the original
|
||||
// pixel coordinate. This will then be clamped to 1.f if it's greater than the control
|
||||
// parameter, which simulates kNearest and kBilerp behavior depending on if it's 0 or 1.
|
||||
if (decalX && decalY) {
|
||||
builder->codeAppendf("half err = max(abs(clampedCoord.x - origCoord.x) * %s.x, "
|
||||
"abs(clampedCoord.y - origCoord.y) * %s.y);",
|
||||
fDecalName.c_str(), fDecalName.c_str());
|
||||
} else if (decalX) {
|
||||
builder->codeAppendf("half err = abs(clampedCoord.x - origCoord.x) * %s.x;",
|
||||
fDecalName.c_str());
|
||||
} else {
|
||||
SkASSERT(decalY);
|
||||
builder->codeAppendf("half err = abs(clampedCoord.y - origCoord.y) * %s.y;",
|
||||
fDecalName.c_str());
|
||||
}
|
||||
|
||||
// Apply a transform to the error rate, which let's us simulate nearest or bilerp filtering
|
||||
// in the same shader. When the texture is nearest filtered, fSizeName.z is set to 1/2 so
|
||||
// this becomes a step function centered at .5 away from the clamped coordinate (but the
|
||||
// domain for decal is inset by .5 so the edge lines up properly). When bilerp, fSizeName.z
|
||||
// is set to 1 and it becomes a simple linear blend between texture and transparent.
|
||||
builder->codeAppendf("if (err > %s.z) { err = 1.0; } else if (%s.z < 1) { err = 0.0; }",
|
||||
fDecalName.c_str(), fDecalName.c_str());
|
||||
builder->codeAppendf("%s = mix(inside, half4(0, 0, 0, 0), err);", outColor);
|
||||
} else {
|
||||
// A simple look up
|
||||
builder->codeAppendf("%s = inside;", outColor);
|
||||
}
|
||||
}
|
||||
|
||||
void GrTextureDomain::GLDomain::setData(const GrGLSLProgramDataManager& pdman,
|
||||
const GrTextureDomain& textureDomain,
|
||||
GrTextureProxy* proxy) {
|
||||
GrTextureProxy* proxy,
|
||||
const GrSamplerState& sampler) {
|
||||
GrTexture* tex = proxy->peekTexture();
|
||||
SkASSERT(fHasMode && textureDomain.mode() == fMode);
|
||||
if (kIgnore_Mode != textureDomain.mode()) {
|
||||
SkASSERT(fHasMode && textureDomain.modeX() == fModeX && textureDomain.modeY() == fModeY);
|
||||
if (kIgnore_Mode != textureDomain.modeX() || kIgnore_Mode != textureDomain.modeY()) {
|
||||
bool sendDecalData = textureDomain.modeX() == kDecal_Mode ||
|
||||
textureDomain.modeY() == kDecal_Mode;
|
||||
|
||||
// If the texture is using nearest filtering, then the decal filter weight should step from
|
||||
// 0 (texture) to 1 (transparent) one half pixel away from the domain. When doing any other
|
||||
// form of filtering, the weight should be 1.0 so that it smoothly interpolates between the
|
||||
// texture and transparent.
|
||||
SkScalar decalFilterWeight = sampler.filter() == GrSamplerState::Filter::kNearest ?
|
||||
SK_ScalarHalf : 1.0f;
|
||||
SkScalar wInv, hInv, h;
|
||||
if (proxy->textureType() == GrTextureType::kRectangle) {
|
||||
wInv = hInv = 1.f;
|
||||
h = tex->height();
|
||||
|
||||
// Don't do any scaling by texture size for decal filter rate, it's already in pixels
|
||||
if (sendDecalData) {
|
||||
pdman.set3f(fDecalUni, 1.f, 1.f, decalFilterWeight);
|
||||
}
|
||||
} else {
|
||||
wInv = SK_Scalar1 / tex->width();
|
||||
hInv = SK_Scalar1 / tex->height();
|
||||
h = 1.f;
|
||||
|
||||
if (sendDecalData) {
|
||||
pdman.set3f(fDecalUni, tex->width(), tex->height(), decalFilterWeight);
|
||||
}
|
||||
}
|
||||
|
||||
float values[kPrevDomainCount] = {
|
||||
@ -213,8 +250,9 @@ void GrTextureDomain::GLDomain::setData(const GrGLSLProgramDataManager& pdman,
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
inline GrFragmentProcessor::OptimizationFlags GrTextureDomainEffect::OptFlags(
|
||||
GrPixelConfig config, GrTextureDomain::Mode mode) {
|
||||
if (mode == GrTextureDomain::kDecal_Mode || !GrPixelConfigIsOpaque(config)) {
|
||||
GrPixelConfig config, GrTextureDomain::Mode modeX, GrTextureDomain::Mode modeY) {
|
||||
if (modeX == GrTextureDomain::kDecal_Mode || modeY == GrTextureDomain::kDecal_Mode ||
|
||||
!GrPixelConfigIsOpaque(config)) {
|
||||
return GrFragmentProcessor::kCompatibleWithCoverageAsAlpha_OptimizationFlag;
|
||||
} else {
|
||||
return GrFragmentProcessor::kCompatibleWithCoverageAsAlpha_OptimizationFlag |
|
||||
@ -228,26 +266,37 @@ std::unique_ptr<GrFragmentProcessor> GrTextureDomainEffect::Make(
|
||||
const SkRect& domain,
|
||||
GrTextureDomain::Mode mode,
|
||||
GrSamplerState::Filter filterMode) {
|
||||
if (GrTextureDomain::kIgnore_Mode == mode ||
|
||||
(GrTextureDomain::kClamp_Mode == mode && can_ignore_rect(proxy.get(), domain))) {
|
||||
return GrSimpleTextureEffect::Make(std::move(proxy), matrix, filterMode);
|
||||
} else {
|
||||
return std::unique_ptr<GrFragmentProcessor>(new GrTextureDomainEffect(
|
||||
std::move(proxy), matrix, domain, mode, filterMode));
|
||||
return Make(std::move(proxy), matrix, domain, mode, mode,
|
||||
GrSamplerState(GrSamplerState::WrapMode::kClamp, filterMode));
|
||||
}
|
||||
|
||||
std::unique_ptr<GrFragmentProcessor> GrTextureDomainEffect::Make(
|
||||
sk_sp<GrTextureProxy> proxy,
|
||||
const SkMatrix& matrix,
|
||||
const SkRect& domain,
|
||||
GrTextureDomain::Mode modeX,
|
||||
GrTextureDomain::Mode modeY,
|
||||
const GrSamplerState& sampler) {
|
||||
// If both domain modes happen to be ignore, it would be faster to just drop the domain logic
|
||||
// entirely Technically, we could also use the simple texture effect if the domain modes agree
|
||||
// with the sampler modes and the proxy is the same size as the domain. It's a lot easier for
|
||||
// calling code to detect these cases and handle it themselves.
|
||||
return std::unique_ptr<GrFragmentProcessor>(new GrTextureDomainEffect(
|
||||
std::move(proxy), matrix, domain, modeX, modeY, sampler));
|
||||
}
|
||||
|
||||
GrTextureDomainEffect::GrTextureDomainEffect(sk_sp<GrTextureProxy> proxy,
|
||||
const SkMatrix& matrix,
|
||||
const SkRect& domain,
|
||||
GrTextureDomain::Mode mode,
|
||||
GrSamplerState::Filter filterMode)
|
||||
: INHERITED(kGrTextureDomainEffect_ClassID, OptFlags(proxy->config(), mode))
|
||||
GrTextureDomain::Mode modeX,
|
||||
GrTextureDomain::Mode modeY,
|
||||
const GrSamplerState& sampler)
|
||||
: INHERITED(kGrTextureDomainEffect_ClassID, OptFlags(proxy->config(), modeX, modeY))
|
||||
, fCoordTransform(matrix, proxy.get())
|
||||
, fTextureDomain(proxy.get(), domain, mode)
|
||||
, fTextureSampler(std::move(proxy), filterMode) {
|
||||
SkASSERT(mode != GrTextureDomain::kRepeat_Mode ||
|
||||
filterMode == GrSamplerState::Filter::kNearest);
|
||||
, fTextureDomain(proxy.get(), domain, modeX, modeY)
|
||||
, fTextureSampler(std::move(proxy), sampler) {
|
||||
SkASSERT((modeX != GrTextureDomain::kRepeat_Mode && modeY != GrTextureDomain::kRepeat_Mode) ||
|
||||
sampler.filter() == GrSamplerState::Filter::kNearest);
|
||||
this->addCoordTransform(&fCoordTransform);
|
||||
this->setTextureSamplerCnt(1);
|
||||
}
|
||||
@ -293,7 +342,7 @@ GrGLSLFragmentProcessor* GrTextureDomainEffect::onCreateGLSLInstance() const {
|
||||
const GrTextureDomain& domain = tde.fTextureDomain;
|
||||
GrTextureProxy* proxy = tde.textureSampler(0).proxy();
|
||||
|
||||
fGLDomain.setData(pdman, domain, proxy);
|
||||
fGLDomain.setData(pdman, domain, proxy, tde.textureSampler(0).samplerState());
|
||||
}
|
||||
|
||||
private:
|
||||
@ -322,16 +371,21 @@ std::unique_ptr<GrFragmentProcessor> GrTextureDomainEffect::TestCreate(GrProcess
|
||||
domain.fRight = d->fRandom->nextRangeScalar(domain.fLeft, proxy->width());
|
||||
domain.fTop = d->fRandom->nextRangeScalar(0, proxy->height());
|
||||
domain.fBottom = d->fRandom->nextRangeScalar(domain.fTop, proxy->height());
|
||||
GrTextureDomain::Mode mode =
|
||||
GrTextureDomain::Mode modeX =
|
||||
(GrTextureDomain::Mode) d->fRandom->nextULessThan(GrTextureDomain::kModeCount);
|
||||
GrTextureDomain::Mode modeY =
|
||||
(GrTextureDomain::Mode) d->fRandom->nextULessThan(GrTextureDomain::kModeCount);
|
||||
const SkMatrix& matrix = GrTest::TestMatrix(d->fRandom);
|
||||
bool bilerp = mode != GrTextureDomain::kRepeat_Mode ? d->fRandom->nextBool() : false;
|
||||
bool bilerp = modeX != GrTextureDomain::kRepeat_Mode && modeY != GrTextureDomain::kRepeat_Mode ?
|
||||
d->fRandom->nextBool() : false;
|
||||
return GrTextureDomainEffect::Make(
|
||||
std::move(proxy),
|
||||
matrix,
|
||||
domain,
|
||||
mode,
|
||||
bilerp ? GrSamplerState::Filter::kBilerp : GrSamplerState::Filter::kNearest);
|
||||
modeX,
|
||||
modeY,
|
||||
GrSamplerState(GrSamplerState::WrapMode::kClamp, bilerp ?
|
||||
GrSamplerState::Filter::kBilerp : GrSamplerState::Filter::kNearest));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -347,8 +401,9 @@ GrDeviceSpaceTextureDecalFragmentProcessor::GrDeviceSpaceTextureDecalFragmentPro
|
||||
: INHERITED(kGrDeviceSpaceTextureDecalFragmentProcessor_ClassID,
|
||||
kCompatibleWithCoverageAsAlpha_OptimizationFlag)
|
||||
, fTextureSampler(proxy, GrSamplerState::ClampNearest())
|
||||
, fTextureDomain(proxy.get(), GrTextureDomain::MakeTexelDomain(subset),
|
||||
GrTextureDomain::kDecal_Mode) {
|
||||
, fTextureDomain(proxy.get(),
|
||||
GrTextureDomain::MakeTexelDomain(subset, GrTextureDomain::kDecal_Mode),
|
||||
GrTextureDomain::kDecal_Mode, GrTextureDomain::kDecal_Mode) {
|
||||
this->setTextureSamplerCnt(1);
|
||||
fDeviceSpaceOffset.fX = deviceSpaceOffset.fX - subset.fLeft;
|
||||
fDeviceSpaceOffset.fY = deviceSpaceOffset.fY - subset.fTop;
|
||||
@ -400,7 +455,8 @@ GrGLSLFragmentProcessor* GrDeviceSpaceTextureDecalFragmentProcessor::onCreateGLS
|
||||
GrTextureProxy* proxy = dstdfp.textureSampler(0).proxy();
|
||||
GrTexture* texture = proxy->peekTexture();
|
||||
|
||||
fGLDomain.setData(pdman, dstdfp.fTextureDomain, proxy);
|
||||
fGLDomain.setData(pdman, dstdfp.fTextureDomain, proxy,
|
||||
dstdfp.textureSampler(0).samplerState());
|
||||
float iw = 1.f / texture->width();
|
||||
float ih = 1.f / texture->height();
|
||||
float scaleAndTransData[4] = {
|
||||
|
@ -45,7 +45,7 @@ public:
|
||||
|
||||
static const GrTextureDomain& IgnoredDomain() {
|
||||
static const GrTextureDomain gDomain((GrTextureProxy*)nullptr,
|
||||
SkRect::MakeEmpty(), kIgnore_Mode);
|
||||
SkRect::MakeEmpty(), kIgnore_Mode, kIgnore_Mode);
|
||||
return gDomain;
|
||||
}
|
||||
|
||||
@ -53,28 +53,38 @@ public:
|
||||
* @param index Pass a value >= 0 if using multiple texture domains in the same effect.
|
||||
* It is used to keep inserted variables from causing name collisions.
|
||||
*/
|
||||
GrTextureDomain(GrTextureProxy*, const SkRect& domain, Mode, int index = -1);
|
||||
GrTextureDomain(GrTextureProxy*, const SkRect& domain, Mode modeX, Mode modeY, int index = -1);
|
||||
|
||||
GrTextureDomain(const GrTextureDomain&) = default;
|
||||
|
||||
const SkRect& domain() const { return fDomain; }
|
||||
Mode mode() const { return fMode; }
|
||||
Mode modeX() const { return fModeX; }
|
||||
Mode modeY() const { return fModeY; }
|
||||
|
||||
/* Computes a domain that bounds all the texels in texelRect. Note that with bilerp enabled
|
||||
texels neighboring the domain may be read. */
|
||||
static const SkRect MakeTexelDomain(const SkIRect& texelRect) {
|
||||
return SkRect::Make(texelRect);
|
||||
/*
|
||||
* Computes a domain that bounds all the texels in texelRect, possibly insetting by half a pixel
|
||||
* depending on the mode. The mode is used for both axes.
|
||||
*/
|
||||
static const SkRect MakeTexelDomain(const SkIRect& texelRect, Mode mode) {
|
||||
return MakeTexelDomain(texelRect, mode, mode);
|
||||
}
|
||||
|
||||
static const SkRect MakeTexelDomainForMode(const SkIRect& texelRect, Mode mode) {
|
||||
// For Clamp mode, inset by half a texel.
|
||||
SkScalar inset = (mode == kClamp_Mode && !texelRect.isEmpty()) ? SK_ScalarHalf : 0;
|
||||
return SkRect::MakeLTRB(texelRect.fLeft + inset, texelRect.fTop + inset,
|
||||
texelRect.fRight - inset, texelRect.fBottom - inset);
|
||||
static const SkRect MakeTexelDomain(const SkIRect& texelRect, Mode modeX, Mode modeY) {
|
||||
// For Clamp and decal modes, inset by half a texel
|
||||
SkScalar insetX = ((modeX == kClamp_Mode || modeX == kDecal_Mode) && texelRect.width() > 0)
|
||||
? SK_ScalarHalf : 0;
|
||||
SkScalar insetY = ((modeY == kClamp_Mode || modeY == kDecal_Mode) && texelRect.height() > 0)
|
||||
? SK_ScalarHalf : 0;
|
||||
return SkRect::MakeLTRB(texelRect.fLeft + insetX, texelRect.fTop + insetY,
|
||||
texelRect.fRight - insetX, texelRect.fBottom - insetY);
|
||||
}
|
||||
|
||||
bool operator==(const GrTextureDomain& that) const {
|
||||
return fMode == that.fMode && (kIgnore_Mode == fMode || fDomain == that.fDomain);
|
||||
return fModeX == that.fModeX && fModeY == that.fModeY &&
|
||||
(kIgnore_Mode == fModeX || (fDomain.fLeft == that.fDomain.fLeft &&
|
||||
fDomain.fRight == that.fDomain.fRight)) &&
|
||||
(kIgnore_Mode == fModeY || (fDomain.fTop == that.fDomain.fTop &&
|
||||
fDomain.fBottom == that.fDomain.fBottom));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -115,10 +125,12 @@ public:
|
||||
* texture domain. The rectangle is automatically adjusted to account for the texture's
|
||||
* origin.
|
||||
*/
|
||||
void setData(const GrGLSLProgramDataManager&, const GrTextureDomain&, GrTextureProxy*);
|
||||
void setData(const GrGLSLProgramDataManager&, const GrTextureDomain&, GrTextureProxy*,
|
||||
const GrSamplerState& sampler);
|
||||
|
||||
enum {
|
||||
kDomainKeyBits = 2, // See DomainKey().
|
||||
kModeBits = 2, // See DomainKey().
|
||||
kDomainKeyBits = 4
|
||||
};
|
||||
|
||||
/**
|
||||
@ -126,21 +138,28 @@ public:
|
||||
* computed key. The returned will be limited to the lower kDomainKeyBits bits.
|
||||
*/
|
||||
static uint32_t DomainKey(const GrTextureDomain& domain) {
|
||||
GR_STATIC_ASSERT(kModeCount <= (1 << kDomainKeyBits));
|
||||
return domain.mode();
|
||||
GR_STATIC_ASSERT(kModeCount <= (1 << kModeBits));
|
||||
return domain.modeX() | (domain.modeY() << kModeBits);
|
||||
}
|
||||
|
||||
private:
|
||||
static const int kPrevDomainCount = 4;
|
||||
SkDEBUGCODE(Mode fMode;)
|
||||
SkDEBUGCODE(Mode fModeX;)
|
||||
SkDEBUGCODE(Mode fModeY;)
|
||||
SkDEBUGCODE(bool fHasMode = false;)
|
||||
GrGLSLProgramDataManager::UniformHandle fDomainUni;
|
||||
SkString fDomainName;
|
||||
|
||||
// Only initialized if the domain has at least one decal axis
|
||||
GrGLSLProgramDataManager::UniformHandle fDecalUni;
|
||||
SkString fDecalName;
|
||||
|
||||
float fPrevDomain[kPrevDomainCount];
|
||||
};
|
||||
|
||||
protected:
|
||||
Mode fMode;
|
||||
Mode fModeX;
|
||||
Mode fModeY;
|
||||
SkRect fDomain;
|
||||
int fIndex;
|
||||
};
|
||||
@ -153,9 +172,16 @@ public:
|
||||
static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy>,
|
||||
const SkMatrix&,
|
||||
const SkRect& domain,
|
||||
GrTextureDomain::Mode,
|
||||
GrTextureDomain::Mode mode,
|
||||
GrSamplerState::Filter filterMode);
|
||||
|
||||
static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy>,
|
||||
const SkMatrix&,
|
||||
const SkRect& domain,
|
||||
GrTextureDomain::Mode modeX,
|
||||
GrTextureDomain::Mode modeY,
|
||||
const GrSamplerState& sampler);
|
||||
|
||||
const char* name() const override { return "TextureDomain"; }
|
||||
|
||||
std::unique_ptr<GrFragmentProcessor> clone() const override {
|
||||
@ -181,12 +207,14 @@ private:
|
||||
GrTextureDomainEffect(sk_sp<GrTextureProxy>,
|
||||
const SkMatrix&,
|
||||
const SkRect& domain,
|
||||
GrTextureDomain::Mode,
|
||||
GrSamplerState::Filter);
|
||||
GrTextureDomain::Mode modeX,
|
||||
GrTextureDomain::Mode modeY,
|
||||
const GrSamplerState&);
|
||||
|
||||
explicit GrTextureDomainEffect(const GrTextureDomainEffect&);
|
||||
|
||||
static OptimizationFlags OptFlags(GrPixelConfig config, GrTextureDomain::Mode mode);
|
||||
static OptimizationFlags OptFlags(GrPixelConfig config, GrTextureDomain::Mode modeX,
|
||||
GrTextureDomain::Mode modeY);
|
||||
|
||||
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
|
||||
|
||||
|
@ -187,16 +187,19 @@ std::unique_ptr<GrFragmentProcessor> SkImageShader::asFragmentProcessor(
|
||||
|
||||
GrSamplerState::WrapMode wrapModes[] = {tile_mode_to_wrap_mode(fTileModeX),
|
||||
tile_mode_to_wrap_mode(fTileModeY)};
|
||||
if ((wrapModes[0] == GrSamplerState::WrapMode::kClampToBorder ||
|
||||
wrapModes[1] == GrSamplerState::WrapMode::kClampToBorder) &&
|
||||
!args.fContext->contextPriv().caps()->clampToBorderSupport()) {
|
||||
// HW clamp to border is unavailable, so fall back to clamp for now
|
||||
// TODO(michaelludwig): If clamp-to-border is selected but is unsupported, the texture
|
||||
// domain effect could be used to emulate the decal effect.
|
||||
|
||||
// If either domainX or domainY are un-ignored, a texture domain effect has to be used to
|
||||
// implement the decal mode (while leaving non-decal axes alone). The wrap mode originally
|
||||
// clamp-to-border is reset to clamp since the hw cannot implement it directly.
|
||||
GrTextureDomain::Mode domainX = GrTextureDomain::kIgnore_Mode;
|
||||
GrTextureDomain::Mode domainY = GrTextureDomain::kIgnore_Mode;
|
||||
if (!args.fContext->contextPriv().caps()->clampToBorderSupport()) {
|
||||
if (wrapModes[0] == GrSamplerState::WrapMode::kClampToBorder) {
|
||||
domainX = GrTextureDomain::kDecal_Mode;
|
||||
wrapModes[0] = GrSamplerState::WrapMode::kClamp;
|
||||
}
|
||||
if (wrapModes[1] == GrSamplerState::WrapMode::kClampToBorder) {
|
||||
domainY = GrTextureDomain::kDecal_Mode;
|
||||
wrapModes[1] = GrSamplerState::WrapMode::kClamp;
|
||||
}
|
||||
}
|
||||
@ -224,10 +227,20 @@ std::unique_ptr<GrFragmentProcessor> SkImageShader::asFragmentProcessor(
|
||||
|
||||
std::unique_ptr<GrFragmentProcessor> inner;
|
||||
if (doBicubic) {
|
||||
inner = GrBicubicEffect::Make(std::move(proxy), lmInverse, wrapModes);
|
||||
// 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);
|
||||
} else {
|
||||
if (domainX != GrTextureDomain::kIgnore_Mode || domainY != GrTextureDomain::kIgnore_Mode) {
|
||||
SkRect domain = GrTextureDomain::MakeTexelDomain(
|
||||
SkIRect::MakeWH(proxy->width(), proxy->height()),
|
||||
domainX, domainY);
|
||||
inner = GrTextureDomainEffect::Make(std::move(proxy), lmInverse, domain,
|
||||
domainX, domainY, samplerState);
|
||||
} else {
|
||||
inner = GrSimpleTextureEffect::Make(std::move(proxy), lmInverse, samplerState);
|
||||
}
|
||||
}
|
||||
inner = GrColorSpaceXformEffect::Make(std::move(inner), fImage->colorSpace(),
|
||||
fImage->alphaType(),
|
||||
args.fDstColorSpaceInfo->colorSpace());
|
||||
|
Loading…
Reference in New Issue
Block a user