Merge ShaderMode and FilterLogic enums in GrTextureEffect
Change-Id: I2523b79e6cf5654daba03aa837d05a76d8ca9f66
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297189
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
diff --git a/src/gpu/effects/GrTextureEffect.cpp b/src/gpu/effects/GrTextureEffect.cpp
index 6819677..554fd1d 100644
--- a/src/gpu/effects/GrTextureEffect.cpp
+++ b/src/gpu/effects/GrTextureEffect.cpp
@@ -110,7 +110,7 @@
r.fShaderSubset = r.fShaderClamp = {0, 0};
return r;
}
- r.fShaderMode = static_cast<ShaderMode>(mode);
+ r.fShaderMode = GetShaderMode(mode, filter);
r.fHWMode = Mode::kClamp;
return r;
};
@@ -142,8 +142,7 @@
fHWSampler.wrapModeY() == GrSamplerState::WrapMode::kClampToBorder) {
return true;
}
- if (fShaderModes[0] == ShaderMode::kClampToBorder ||
- fShaderModes[1] == ShaderMode::kClampToBorder) {
+ if (ShaderModeIsClampToBorder(fShaderModes[0]) || ShaderModeIsClampToBorder(fShaderModes[1])) {
return fBorder[3] < 1.f;
}
return false;
@@ -258,30 +257,34 @@
lazyProxyNormalization)));
}
-GrTextureEffect::FilterLogic GrTextureEffect::GetFilterLogic(ShaderMode mode,
- GrSamplerState::Filter filter) {
+GrTextureEffect::ShaderMode GrTextureEffect::GetShaderMode(GrSamplerState::WrapMode mode,
+ GrSamplerState::Filter filter) {
switch (mode) {
- case ShaderMode::kMirrorRepeat:
- case ShaderMode::kNone:
- case ShaderMode::kClamp:
- return FilterLogic::kNone;
- case ShaderMode::kRepeat:
+ case GrSamplerState::WrapMode::kMirrorRepeat:
+ return ShaderMode::kMirrorRepeat;
+ case GrSamplerState::WrapMode::kClamp:
+ return ShaderMode::kClamp;
+ case GrSamplerState::WrapMode::kRepeat:
switch (filter) {
case GrSamplerState::Filter::kNearest:
- return FilterLogic::kNone;
+ return ShaderMode::kRepeatNearest;
case GrSamplerState::Filter::kBilerp:
- return FilterLogic::kRepeatBilerp;
+ return ShaderMode::kRepeatBilerp;
case GrSamplerState::Filter::kMipMap:
- return FilterLogic::kRepeatMipMap;
+ return ShaderMode::kRepeatMipMap;
}
SkUNREACHABLE;
- case ShaderMode::kClampToBorder:
- return filter > GrSamplerState::Filter::kNearest ? FilterLogic::kClampToBorderFilter
- : FilterLogic::kClampToBorderNearest;
+ case GrSamplerState::WrapMode::kClampToBorder:
+ return filter == GrSamplerState::Filter::kNearest ? ShaderMode::kClampToBorderNearest
+ : ShaderMode::kClampToBorderFilter;
}
SkUNREACHABLE;
}
+inline bool GrTextureEffect::ShaderModeIsClampToBorder(ShaderMode m) {
+ return m == ShaderMode::kClampToBorderNearest || m == ShaderMode::kClampToBorderFilter;
+}
+
GrGLSLFragmentProcessor* GrTextureEffect::onCreateGLSLInstance() const {
class Impl : public GrGLSLFragmentProcessor {
UniformHandle fSubsetUni;
@@ -362,24 +365,55 @@
const auto& m = te.fShaderModes;
GrTextureType textureType = te.fSampler.proxy()->backendFormat().textureType();
bool normCoords = textureType != GrTextureType::kRectangle;
- auto filter = te.fSampler.samplerState().filter();
- FilterLogic filterLogic[2] = {GetFilterLogic(m[0], filter),
- GetFilterLogic(m[1], filter)};
const char* borderName = nullptr;
- if (te.fShaderModes[0] == ShaderMode::kClampToBorder ||
- te.fShaderModes[1] == ShaderMode::kClampToBorder) {
+ if (te.hasClampToBorderShaderMode()) {
fBorderUni = args.fUniformHandler->addUniform(
&te, kFragment_GrShaderFlag, kHalf4_GrSLType, "border", &borderName);
}
auto modeUsesSubset = [](ShaderMode m) {
- return m == ShaderMode::kRepeat || m == ShaderMode::kMirrorRepeat ||
- m == ShaderMode::kClampToBorder;
+ switch (m) {
+ case ShaderMode::kNone: return false;
+ case ShaderMode::kClamp: return false;
+ case ShaderMode::kRepeatNearest: return true;
+ case ShaderMode::kRepeatBilerp: return true;
+ case ShaderMode::kRepeatMipMap: return true;
+ case ShaderMode::kMirrorRepeat: return true;
+ case ShaderMode::kClampToBorderNearest: return true;
+ case ShaderMode::kClampToBorderFilter: return true;
+ }
+ SkUNREACHABLE;
};
- auto modeUsesClamp = [filter](ShaderMode m) {
- return m != ShaderMode::kNone &&
- (m != ShaderMode::kClampToBorder || filter > Filter::kNearest);
+ auto modeUsesClamp = [](ShaderMode m) {
+ switch (m) {
+ case ShaderMode::kNone: return false;
+ case ShaderMode::kClamp: return true;
+ case ShaderMode::kRepeatNearest: return true;
+ case ShaderMode::kRepeatBilerp: return true;
+ case ShaderMode::kRepeatMipMap: return true;
+ case ShaderMode::kMirrorRepeat: return true;
+ case ShaderMode::kClampToBorderNearest: return false;
+ case ShaderMode::kClampToBorderFilter: return true;
+ }
+ SkUNREACHABLE;
+ };
+
+ // To keep things a little simpler, when we have filtering logic in the shader we
+ // operate on unnormalized texture coordinates. We will add a uniform that stores
+ // {w, h, 1/w, 1/h} in a float4 below.
+ auto modeRequiresUnormCoords = [](ShaderMode m) {
+ switch (m) {
+ case ShaderMode::kNone: return false;
+ case ShaderMode::kClamp: return false;
+ case ShaderMode::kRepeatNearest: return true;
+ case ShaderMode::kRepeatBilerp: return true;
+ case ShaderMode::kRepeatMipMap: return true;
+ case ShaderMode::kMirrorRepeat: return false;
+ case ShaderMode::kClampToBorderNearest: return true;
+ case ShaderMode::kClampToBorderFilter: return true;
+ }
+ SkUNREACHABLE;
};
bool useSubset[2] = {modeUsesSubset(m[0]), modeUsesSubset(m[1])};
@@ -397,12 +431,9 @@
&te, kFragment_GrShaderFlag, kFloat4_GrSLType, "clamp", &clampName);
}
- // To keep things a little simpler, when we have filtering logic in the shader we
- // operate on unnormalized texture coordinates. We add a uniform that stores
- // {w, h, 1/w, 1/h} in a float4.
const char* norm = nullptr;
- if (normCoords && (filterLogic[0] != FilterLogic::kNone ||
- filterLogic[1] != FilterLogic::kNone)) {
+ if (normCoords && (modeRequiresUnormCoords(m[0]) ||
+ modeRequiresUnormCoords(m[1]))) {
// TODO: Detect support for textureSize() or polyfill textureSize() in SkSL and
// always use?
fNormUni = args.fUniformHandler->addUniform(&te, kFragment_GrShaderFlag,
@@ -436,55 +467,56 @@
// These modes either don't use the subset rect or don't need to map the
// coords to be within the subset.
case ShaderMode::kNone:
- case ShaderMode::kClampToBorder:
+ case ShaderMode::kClampToBorderNearest:
+ case ShaderMode::kClampToBorderFilter:
case ShaderMode::kClamp:
fb->codeAppendf("subsetCoord.%s = inCoord.%s;", coordSwizzle,
coordSwizzle);
break;
- case ShaderMode::kRepeat:
- if (filter == Filter::kMipMap) {
- // The approach here is to generate two sets of texture coords that
- // are both "moving" at the same speed (if not direction) as
- // inCoords. We accomplish that by using two out of phase mirror
- // repeat coords. We will always sample using both coords but the
- // read from the upward sloping one is selected using a weight
- // that transitions from one set to the other near the reflection
- // point. Like the coords, the weight is a saw-tooth function,
- // phase-shifted, vertically translated, and then clamped to 0..1.
- // TODO: Skip this and use textureGrad() when available.
- SkASSERT(extraCoord);
- SkASSERT(coordWeight);
- fb->codeAppend("{");
- fb->codeAppendf("float w = %s.%s - %s.%s;", subsetName,
- subsetStopSwizzle, subsetName, subsetStartSwizzle);
- fb->codeAppendf("float w2 = 2 * w;");
- fb->codeAppendf("float d = inCoord.%s - %s.%s;", coordSwizzle,
- subsetName, subsetStartSwizzle);
- fb->codeAppend("float m = mod(d, w2);");
- fb->codeAppend("float o = mix(m, w2 - m, step(w, m));");
- fb->codeAppendf("subsetCoord.%s = o + %s.%s;", coordSwizzle,
- subsetName, subsetStartSwizzle);
- fb->codeAppendf("%s = w - o + %s.%s;", extraCoord, subsetName,
- subsetStartSwizzle);
- // coordWeight is used as the third param of mix() to blend between a
- // sample taken using subsetCoord and a sample at extraCoord.
- fb->codeAppend("float hw = w/2;");
- fb->codeAppend("float n = mod(d - hw, w2);");
- fb->codeAppendf(
- "%s = saturate(half(mix(n, w2 - n, step(w, n)) - hw + "
- "0.5));",
- coordWeight);
- fb->codeAppend("}");
- } else {
- fb->codeAppendf(
- "subsetCoord.%s = mod(inCoord.%s - %s.%s, %s.%s - %s.%s) + "
- "%s.%s;",
- coordSwizzle, coordSwizzle, subsetName, subsetStartSwizzle,
- subsetName, subsetStopSwizzle, subsetName,
- subsetStartSwizzle, subsetName, subsetStartSwizzle);
- }
+ case ShaderMode::kRepeatNearest:
+ case ShaderMode::kRepeatBilerp:
+ fb->codeAppendf(
+ "subsetCoord.%s = mod(inCoord.%s - %s.%s, %s.%s - %s.%s) + "
+ "%s.%s;",
+ coordSwizzle, coordSwizzle, subsetName, subsetStartSwizzle,
+ subsetName, subsetStopSwizzle, subsetName, subsetStartSwizzle,
+ subsetName, subsetStartSwizzle);
break;
- case ShaderMode::kMirrorRepeat: {
+ case ShaderMode::kRepeatMipMap:
+ // The approach here is to generate two sets of texture coords that
+ // are both "moving" at the same speed (if not direction) as
+ // inCoords. We accomplish that by using two out of phase mirror
+ // repeat coords. We will always sample using both coords but the
+ // read from the upward sloping one is selected using a weight
+ // that transitions from one set to the other near the reflection
+ // point. Like the coords, the weight is a saw-tooth function,
+ // phase-shifted, vertically translated, and then clamped to 0..1.
+ // TODO: Skip this and use textureGrad() when available.
+ SkASSERT(extraCoord);
+ SkASSERT(coordWeight);
+ fb->codeAppend("{");
+ fb->codeAppendf("float w = %s.%s - %s.%s;", subsetName,
+ subsetStopSwizzle, subsetName, subsetStartSwizzle);
+ fb->codeAppendf("float w2 = 2 * w;");
+ fb->codeAppendf("float d = inCoord.%s - %s.%s;", coordSwizzle,
+ subsetName, subsetStartSwizzle);
+ fb->codeAppend("float m = mod(d, w2);");
+ fb->codeAppend("float o = mix(m, w2 - m, step(w, m));");
+ fb->codeAppendf("subsetCoord.%s = o + %s.%s;", coordSwizzle, subsetName,
+ subsetStartSwizzle);
+ fb->codeAppendf("%s = w - o + %s.%s;", extraCoord, subsetName,
+ subsetStartSwizzle);
+ // coordWeight is used as the third param of mix() to blend between a
+ // sample taken using subsetCoord and a sample at extraCoord.
+ fb->codeAppend("float hw = w/2;");
+ fb->codeAppend("float n = mod(d - hw, w2);");
+ fb->codeAppendf(
+ "%s = saturate(half(mix(n, w2 - n, step(w, n)) - hw + "
+ "0.5));",
+ coordWeight);
+ fb->codeAppend("}");
+ break;
+ case ShaderMode::kMirrorRepeat:
fb->codeAppend("{");
fb->codeAppendf("float w = %s.%s - %s.%s;", subsetName,
subsetStopSwizzle, subsetName, subsetStartSwizzle);
@@ -495,7 +527,6 @@
coordSwizzle, subsetName, subsetStartSwizzle);
fb->codeAppend("}");
break;
- }
}
};
@@ -518,12 +549,12 @@
const char* repeatCoordWeightX = nullptr;
const char* extraRepeatCoordY = nullptr;
const char* repeatCoordWeightY = nullptr;
- if (filterLogic[0] == FilterLogic::kRepeatMipMap) {
+ if (m[0] == ShaderMode::kRepeatMipMap) {
fb->codeAppend("float extraRepeatCoordX; half repeatCoordWeightX;");
extraRepeatCoordX = "extraRepeatCoordX";
repeatCoordWeightX = "repeatCoordWeightX";
}
- if (filterLogic[1] == FilterLogic::kRepeatMipMap) {
+ if (m[1] == ShaderMode::kRepeatMipMap) {
fb->codeAppend("float extraRepeatCoordY; half repeatCoordWeightY;");
extraRepeatCoordY = "extraRepeatCoordY";
repeatCoordWeightY = "repeatCoordWeightY";
@@ -540,11 +571,11 @@
clampCoord(useClamp[1], "y", "y", "w");
// Additional clamping for the extra coords for kRepeatMipMap.
- if (filterLogic[0] == FilterLogic::kRepeatMipMap) {
+ if (m[0] == ShaderMode::kRepeatMipMap) {
fb->codeAppendf("extraRepeatCoordX = clamp(extraRepeatCoordX, %s.x, %s.z);",
clampName, clampName);
}
- if (filterLogic[1] == FilterLogic::kRepeatMipMap) {
+ if (m[1] == ShaderMode::kRepeatMipMap) {
fb->codeAppendf("extraRepeatCoordY = clamp(extraRepeatCoordY, %s.y, %s.w);",
clampName, clampName);
}
@@ -552,8 +583,7 @@
// Do the 2 or 4 texture reads for kRepeatMipMap and then apply the weight(s)
// to blend between them. If neither direction is kRepeatMipMap do a single
// read at clampedCoord.
- if (filterLogic[0] == FilterLogic::kRepeatMipMap &&
- filterLogic[1] == FilterLogic::kRepeatMipMap) {
+ if (m[0] == ShaderMode::kRepeatMipMap && m[1] == ShaderMode::kRepeatMipMap) {
fb->codeAppendf(
"half4 textureColor ="
" mix(mix(%s, %s, repeatCoordWeightX),"
@@ -564,11 +594,11 @@
read("float2(clampedCoord.x, extraRepeatCoordY)").c_str(),
read("float2(extraRepeatCoordX, extraRepeatCoordY)").c_str());
- } else if (filterLogic[0] == FilterLogic::kRepeatMipMap) {
+ } else if (m[0] == ShaderMode::kRepeatMipMap) {
fb->codeAppendf("half4 textureColor = mix(%s, %s, repeatCoordWeightX);",
read("clampedCoord").c_str(),
read("float2(extraRepeatCoordX, clampedCoord.y)").c_str());
- } else if (filterLogic[1] == FilterLogic::kRepeatMipMap) {
+ } else if (m[1] == ShaderMode::kRepeatMipMap) {
fb->codeAppendf("half4 textureColor = mix(%s, %s, repeatCoordWeightY);",
read("clampedCoord").c_str(),
read("float2(clampedCoord.x, extraRepeatCoordY)").c_str());
@@ -583,15 +613,13 @@
// Calculate the amount the coord moved for clamping. This will be used
// to implement shader-based filtering for kClampToBorder and kRepeat.
- if (filterLogic[0] == FilterLogic::kRepeatBilerp ||
- filterLogic[0] == FilterLogic::kClampToBorderFilter) {
+ if (m[0] == ShaderMode::kRepeatBilerp || m[0] == ShaderMode::kClampToBorderFilter) {
fb->codeAppend("half errX = half(subsetCoord.x - clampedCoord.x);");
fb->codeAppendf("float repeatCoordX = errX > 0 ? %s.x : %s.z;", clampName,
clampName);
repeatBilerpReadX = read("float2(repeatCoordX, clampedCoord.y)");
}
- if (filterLogic[1] == FilterLogic::kRepeatBilerp ||
- filterLogic[1] == FilterLogic::kClampToBorderFilter) {
+ if (m[1] == ShaderMode::kRepeatBilerp || m[1] == ShaderMode::kClampToBorderFilter) {
fb->codeAppend("half errY = half(subsetCoord.y - clampedCoord.y);");
fb->codeAppendf("float repeatCoordY = errY > 0 ? %s.y : %s.w;", clampName,
clampName);
@@ -603,8 +631,7 @@
// or a corner. Then blend the multiple reads using the err values calculated
// above.
const char* ifStr = "if";
- if (filterLogic[0] == FilterLogic::kRepeatBilerp &&
- filterLogic[1] == FilterLogic::kRepeatBilerp) {
+ if (m[0] == ShaderMode::kRepeatBilerp && m[1] == ShaderMode::kRepeatBilerp) {
auto repeatBilerpReadXY = read("float2(repeatCoordX, repeatCoordY)");
fb->codeAppendf(
"if (errX != 0 && errY != 0) {"
@@ -617,14 +644,14 @@
repeatBilerpReadXY.c_str());
ifStr = "else if";
}
- if (filterLogic[0] == FilterLogic::kRepeatBilerp) {
+ if (m[0] == ShaderMode::kRepeatBilerp) {
fb->codeAppendf(
"%s (errX != 0) {"
" textureColor = mix(textureColor, %s, abs(errX));"
"}",
ifStr, repeatBilerpReadX.c_str());
}
- if (filterLogic[1] == FilterLogic::kRepeatBilerp) {
+ if (m[1] == ShaderMode::kRepeatBilerp) {
fb->codeAppendf(
"%s (errY != 0) {"
" textureColor = mix(textureColor, %s, abs(errY));"
@@ -634,25 +661,25 @@
// Do soft edge shader filtering against border color for kClampToBorderFilter using
// the err values calculated above.
- if (filterLogic[0] == FilterLogic::kClampToBorderFilter) {
+ if (m[0] == ShaderMode::kClampToBorderFilter) {
fb->codeAppendf("textureColor = mix(textureColor, %s, min(abs(errX), 1));",
borderName);
}
- if (filterLogic[1] == FilterLogic::kClampToBorderFilter) {
+ if (m[1] == ShaderMode::kClampToBorderFilter) {
fb->codeAppendf("textureColor = mix(textureColor, %s, min(abs(errY), 1));",
borderName);
}
// Do hard-edge shader transition to border color for kClampToBorderNearest at the
// subset boundaries.
- if (filterLogic[0] == FilterLogic::kClampToBorderNearest) {
+ if (m[0] == ShaderMode::kClampToBorderNearest) {
fb->codeAppendf(
"if (inCoord.x < %s.x || inCoord.x > %s.z) {"
" textureColor = %s;"
"}",
subsetName, subsetName, borderName);
}
- if (filterLogic[1] == FilterLogic::kClampToBorderNearest) {
+ if (m[1] == ShaderMode::kClampToBorderNearest) {
fb->codeAppendf(
"if (inCoord.y < %s.y || inCoord.y > %s.w) {"
" textureColor = %s;"
@@ -716,10 +743,7 @@
void GrTextureEffect::onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const {
auto m0 = static_cast<uint32_t>(fShaderModes[0]);
auto m1 = static_cast<uint32_t>(fShaderModes[1]);
- auto filter = fSampler.samplerState().filter();
- auto l0 = static_cast<uint32_t>(GetFilterLogic(fShaderModes[0], filter));
- auto l1 = static_cast<uint32_t>(GetFilterLogic(fShaderModes[1], filter));
- b->add32((l0 << 24) | (l1 << 16) | (m0 << 8) | m1);
+ b->add32((m0 << 16) | m1);
}
bool GrTextureEffect::onIsEqual(const GrFragmentProcessor& other) const {
@@ -730,9 +754,7 @@
if (fSubset != that.fSubset) {
return false;
}
- if ((fShaderModes[0] == ShaderMode::kClampToBorder ||
- fShaderModes[1] == ShaderMode::kClampToBorder) &&
- !std::equal(fBorder, fBorder + 4, that.fBorder)) {
+ if (this->hasClampToBorderShaderMode() && !std::equal(fBorder, fBorder + 4, that.fBorder)) {
return false;
}
return true;