Optimize GrRRectBlurEffect by computing frag pos branchlessly.
This version computes X and Y in parallel and without branching.
Change-Id: I08dd7339f75c6cdd5b4130bf363cac1f527bf6ed
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/295572
Commit-Queue: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/effects/GrRRectBlurEffect.fp b/src/gpu/effects/GrRRectBlurEffect.fp
index b784b07..e76d07f 100644
--- a/src/gpu/effects/GrRRectBlurEffect.fp
+++ b/src/gpu/effects/GrRRectBlurEffect.fp
@@ -173,26 +173,38 @@
}
void main() {
- // warp the fragment position to the appropriate part of the 9patch blur texture
+ // Warp the fragment position to the appropriate part of the 9-patch blur texture by snipping
+ // out the middle section of the proxy rect.
+ half2 translatedFragPos = half2(sk_FragCoord.xy - proxyRect.LT);
+ half2 proxyCenter = half2((proxyRect.RB - proxyRect.LT) * 0.5);
+ half edgeSize = 2.0 * blurRadius + cornerRadius + 0.5;
- half2 rectCenter = half2((proxyRect.xy + proxyRect.zw) / 2.0);
- half2 translatedFragPos = half2(sk_FragCoord.xy - proxyRect.xy);
- half threshold = cornerRadius + 2.0 * blurRadius;
- half2 middle = half2(proxyRect.zw - proxyRect.xy - 2.0 * threshold);
+ // Position the fragment so that (0, 0) marks the center of the proxy rectangle.
+ // Negative coordinates are on the left/top side and positive numbers are on the right/bottom.
+ translatedFragPos -= proxyCenter;
- if (translatedFragPos.x >= threshold && translatedFragPos.x < (middle.x + threshold)) {
- translatedFragPos.x = threshold;
- } else if (translatedFragPos.x >= (middle.x + threshold)) {
- translatedFragPos.x -= middle.x - 1.0;
- }
+ // Temporarily strip off the fragment's sign. x/y are now strictly increasing as we move away
+ // from the center.
+ half2 fragDirection = sign(translatedFragPos);
+ translatedFragPos = abs(translatedFragPos);
- if (translatedFragPos.y > threshold && translatedFragPos.y < (middle.y + threshold)) {
- translatedFragPos.y = threshold;
- } else if (translatedFragPos.y >= (middle.y + threshold)) {
- translatedFragPos.y -= middle.y - 1.0;
- }
+ // Our goal is to snip out the "middle section" of the proxy rect (everything but the edge).
+ // We've repositioned our fragment position so that (0, 0) is the centerpoint and x/y are always
+ // positive, so we can subtract here and interpret negative results as being within the middle
+ // section.
+ translatedFragPos -= proxyCenter - edgeSize;
- half2 proxyDims = half2(2.0 * threshold + 1.0);
+ // Remove the middle section by clamping to zero.
+ translatedFragPos = max(translatedFragPos, 0);
+
+ // Reapply the fragment's sign, so that negative coordinates once again mean left/top side and
+ // positive means bottom/right side.
+ translatedFragPos *= fragDirection;
+
+ // Offset the fragment so that (0, 0) marks the upper-left again, instead of the center point.
+ translatedFragPos += half2(edgeSize);
+
+ half2 proxyDims = half2(2.0 * edgeSize);
half2 texCoord = translatedFragPos / proxyDims;
half4 inputColor = sample(inputFP, sk_InColor);
diff --git a/src/gpu/effects/generated/GrRRectBlurEffect.cpp b/src/gpu/effects/generated/GrRRectBlurEffect.cpp
index 1034ede..0889cef 100644
--- a/src/gpu/effects/generated/GrRRectBlurEffect.cpp
+++ b/src/gpu/effects/generated/GrRRectBlurEffect.cpp
@@ -77,32 +77,30 @@
blurRadiusVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag,
kHalf_GrSLType, "blurRadius");
fragBuilder->codeAppendf(
- "\nhalf2 translatedFragPos = half2(sk_FragCoord.xy - %s.xy);\nhalf threshold = %s "
- "+ 2.0 * %s;\nhalf2 middle = half2((%s.zw - %s.xy) - float(2.0 * threshold));\nif "
- "(translatedFragPos.x >= threshold && translatedFragPos.x < middle.x + threshold) "
- "{\n translatedFragPos.x = threshold;\n} else if (translatedFragPos.x >= "
- "middle.x + threshold) {\n translatedFragPos.x -= middle.x - 1.0;\n}\nif "
- "(translatedFragPos.y > threshold && translatedFragPos.y < middle.y + threshold) "
- "{\n translatedFragPos.y = threshold;",
+ "half2 translatedFragPos = half2(sk_FragCoord.xy - %s.xy);\nhalf2 proxyCenter = "
+ "half2((%s.zw - %s.xy) * 0.5);\nhalf edgeSize = (2.0 * %s + %s) + "
+ "0.5;\ntranslatedFragPos -= proxyCenter;\nhalf2 fragDirection = "
+ "sign(translatedFragPos);\ntranslatedFragPos = "
+ "abs(translatedFragPos);\ntranslatedFragPos -= proxyCenter - "
+ "edgeSize;\ntranslatedFragPos = max(translatedFragPos, 0.0);\ntranslatedFragPos *= "
+ "fragDirection;\ntranslatedFragPos += half2(edgeSize);\nhalf2 proxyDims = "
+ "half2(2.0 * edgeSize);\nhalf2 texCoord = tra",
args.fUniformHandler->getUniformCStr(proxyRectVar),
- args.fUniformHandler->getUniformCStr(cornerRadiusVar),
+ args.fUniformHandler->getUniformCStr(proxyRectVar),
+ args.fUniformHandler->getUniformCStr(proxyRectVar),
args.fUniformHandler->getUniformCStr(blurRadiusVar),
- args.fUniformHandler->getUniformCStr(proxyRectVar),
- args.fUniformHandler->getUniformCStr(proxyRectVar));
- fragBuilder->codeAppendf(
- "\n} else if (translatedFragPos.y >= middle.y + threshold) {\n "
- "translatedFragPos.y -= middle.y - 1.0;\n}\nhalf2 proxyDims = half2(2.0 * "
- "threshold + 1.0);\nhalf2 texCoord = translatedFragPos / proxyDims;");
- SkString _input8208 = SkStringPrintf("%s", args.fInputColor);
- SkString _sample8208;
+ args.fUniformHandler->getUniformCStr(cornerRadiusVar));
+ fragBuilder->codeAppendf("nslatedFragPos / proxyDims;");
+ SkString _input8931 = SkStringPrintf("%s", args.fInputColor);
+ SkString _sample8931;
if (_outer.inputFP_index >= 0) {
- _sample8208 = this->invokeChild(_outer.inputFP_index, _input8208.c_str(), args);
+ _sample8931 = this->invokeChild(_outer.inputFP_index, _input8931.c_str(), args);
} else {
- _sample8208 = _input8208;
+ _sample8931 = _input8931;
}
fragBuilder->codeAppendf(
"\nhalf4 inputColor = %s;\n%s = inputColor * sample(%s, float2(texCoord)).%s;\n",
- _sample8208.c_str(), args.fOutputColor,
+ _sample8931.c_str(), args.fOutputColor,
fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]),
fragBuilder->getProgramBuilder()
->samplerSwizzle(args.fTexSamplers[0])