aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/effects
diff options
context:
space:
mode:
authorGravatar robertphillips <robertphillips@google.com>2016-09-12 17:25:50 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-09-12 17:25:50 -0700
commitf619a7af55d4f54101b8068eeb20569be868a6da (patch)
tree9092831846a32311a79f9f5c008e31391d141598 /src/effects
parent28d5b72d86fdfae20dc47ba548748f119c7273e3 (diff)
Fixup SkRRectsGaussianEdgeShader's shaders
This fixes some visual artifacts in the original CL. GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2335783003 Review-Url: https://codereview.chromium.org/2335783003
Diffstat (limited to 'src/effects')
-rw-r--r--src/effects/SkRRectsGaussianEdgeShader.cpp89
1 files changed, 47 insertions, 42 deletions
diff --git a/src/effects/SkRRectsGaussianEdgeShader.cpp b/src/effects/SkRRectsGaussianEdgeShader.cpp
index d3967dbb44..02e46fb874 100644
--- a/src/effects/SkRRectsGaussianEdgeShader.cpp
+++ b/src/effects/SkRRectsGaussianEdgeShader.cpp
@@ -104,31 +104,34 @@ public:
public:
GLSLRRectsGaussianEdgeFP() { }
+ // This method emits code so that, for each shape, the distance from the edge is returned
+ // in 'outputName' clamped to 0..1 with positive distance being towards the center of the
+ // shape. The distance will have been normalized by the radius.
void emitModeCode(Mode mode,
GrGLSLFPFragmentBuilder* fragBuilder,
const char* posName,
const char* sizesName,
const char* radiiName,
+ const char* padRadName,
const char* outputName,
const char indices[2]) { // how to access the params for the 2 rrects
// positive distance is towards the center of the circle
fragBuilder->codeAppendf("vec2 delta = %s.xy - %s.%s;",
- fragBuilder->fragmentPosition(),
- posName, indices);
+ fragBuilder->fragmentPosition(), posName, indices);
switch (mode) {
case kCircle_Mode:
- fragBuilder->codeAppendf("%s = %s.%c - length(delta);",
- outputName,
- sizesName, indices[0]);
+ fragBuilder->codeAppendf("%s = clamp((%s.%c - length(delta))/%s.y, 0.0, 1.0);",
+ outputName, sizesName, indices[0], padRadName);
break;
case kRect_Mode:
- fragBuilder->codeAppendf("float xDist = %s.%c - abs(delta.x);",
- sizesName, indices[0]);
- fragBuilder->codeAppendf("float yDist = %s.%c - abs(delta.y);",
- sizesName, indices[1]);
- fragBuilder->codeAppendf("%s = min(xDist, yDist);", outputName);
+ fragBuilder->codeAppendf(
+ "vec2 rectDist = vec2(1.0 - clamp((%s.%c - abs(delta.x))/%s.y, 0.0, 1.0),"
+ "1.0 - clamp((%s.%c - abs(delta.y))/%s.y, 0.0, 1.0));",
+ sizesName, indices[0], padRadName,
+ sizesName, indices[1], padRadName);
+ fragBuilder->codeAppendf("%s = 1.0 - length(rectDist);", outputName);
break;
case kSimpleCircular_Mode:
// For the circular round rect we first compute the distance
@@ -136,28 +139,28 @@ public:
// point is in one of the circular corners. We then compute the
// distance from the corner and then use the multiplier to mask
// between the two distances.
- fragBuilder->codeAppendf("float xDist = %s.%c - abs(delta.x);",
- sizesName, indices[0]);
- fragBuilder->codeAppendf("float yDist = %s.%c - abs(delta.y);",
- sizesName, indices[1]);
+ fragBuilder->codeAppendf("float xDist = clamp((%s.%c - abs(delta.x))/%s.y,"
+ " 0.0, 1.0);",
+ sizesName, indices[0], padRadName);
+ fragBuilder->codeAppendf("float yDist = clamp((%s.%c - abs(delta.y))/%s.y,"
+ "0.0, 1.0);",
+ sizesName, indices[1], padRadName);
fragBuilder->codeAppend("float rectDist = min(xDist, yDist);");
fragBuilder->codeAppendf("vec2 cornerCenter = %s.%s - %s.%s;",
- sizesName, indices,
- radiiName, indices);
+ sizesName, indices, radiiName, indices);
fragBuilder->codeAppend("delta = vec2(abs(delta.x) - cornerCenter.x,"
"abs(delta.y) - cornerCenter.y);");
- fragBuilder->codeAppendf("xDist = %s.%c - abs(delta.x);",
- radiiName, indices[0]);
- fragBuilder->codeAppendf("yDist = %s.%c - abs(delta.y);",
- radiiName, indices[1]);
+ fragBuilder->codeAppendf("xDist = %s.%c - abs(delta.x);", radiiName, indices[0]);
+ fragBuilder->codeAppendf("yDist = %s.%c - abs(delta.y);", radiiName, indices[1]);
fragBuilder->codeAppend("float cornerDist = min(xDist, yDist);");
fragBuilder->codeAppend("float multiplier = step(0.0, cornerDist);");
fragBuilder->codeAppendf("delta += %s.%s;", radiiName, indices);
- fragBuilder->codeAppendf("cornerDist = 2.0 * %s.%c - length(delta);",
- radiiName, indices[0]);
+ fragBuilder->codeAppendf("cornerDist = clamp((2.0 * %s.%c - length(delta))/%s.y,"
+ "0.0, 1.0);",
+ radiiName, indices[0], padRadName);
fragBuilder->codeAppendf("%s = (multiplier * cornerDist) +"
"((1.0-multiplier) * rectDist);",
@@ -180,9 +183,11 @@ public:
kVec4f_GrSLType, kDefault_GrSLPrecision,
"Sizes", &sizesUniName);
const char* radiiUniName = nullptr;
- fRadiiUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
- kVec4f_GrSLType, kDefault_GrSLPrecision,
- "Radii", &radiiUniName);
+ if (fp.fFirstMode == kSimpleCircular_Mode || fp.fSecondMode == kSimpleCircular_Mode) {
+ fRadiiUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
+ kVec4f_GrSLType, kDefault_GrSLPrecision,
+ "Radii", &radiiUniName);
+ }
const char* padRadUniName = nullptr;
fPadRadUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
kVec2f_GrSLType, kDefault_GrSLPrecision,
@@ -191,25 +196,22 @@ public:
fragBuilder->codeAppend("float firstDist;");
fragBuilder->codeAppend("{");
this->emitModeCode(fp.firstMode(), fragBuilder,
- positionsUniName, sizesUniName, radiiUniName, "firstDist", "xy");
+ positionsUniName, sizesUniName, radiiUniName,
+ padRadUniName, "firstDist", "xy");
fragBuilder->codeAppend("}");
fragBuilder->codeAppend("float secondDist;");
fragBuilder->codeAppend("{");
this->emitModeCode(fp.secondMode(), fragBuilder,
- positionsUniName, sizesUniName, radiiUniName, "secondDist", "zw");
+ positionsUniName, sizesUniName, radiiUniName,
+ padRadUniName, "secondDist", "zw");
fragBuilder->codeAppend("}");
- // Here use the sign of the distance to the two round rects to mask off the different
- // cases.
- fragBuilder->codeAppend("float in1 = step(0.0f, firstDist);");
- fragBuilder->codeAppend("float in2 = step(0.0f, secondDist);");
- fragBuilder->codeAppend("float dist = "
- "in1*in2 * min(firstDist, secondDist);"
- "in1*(1.0-in2) * firstDist +"
- "(1.0-in1)*in2 * secondDist;");
+ fragBuilder->codeAppendf("float dist = %s.y * firstDist * secondDist;",
+ padRadUniName);
// Finally use the distance to apply the Gaussian edge
+ // TODO: we undo the multiply by the radius here - we should just skip both
fragBuilder->codeAppendf("float factor = 1.0 - clamp((dist - %s.x)/%s.y, 0.0, 1.0);",
padRadUniName, padRadUniName);
fragBuilder->codeAppend("factor = exp(-factor * factor * 4.0) - 0.018;");
@@ -243,13 +245,16 @@ public:
0.5f * second.rect().width(),
0.5f * second.rect().height());
- // This is a bit of overkill since fX should equal fY for both round rects but it
- // makes the shader code simpler.
- pdman.set4f(fRadiiUni,
- 0.5f * first.getSimpleRadii().fX,
- 0.5f * first.getSimpleRadii().fY,
- 0.5f * second.getSimpleRadii().fX,
- 0.5f * second.getSimpleRadii().fY);
+ if (edgeFP.firstMode() == kSimpleCircular_Mode ||
+ edgeFP.secondMode() == kSimpleCircular_Mode) {
+ // This is a bit of overkill since fX should equal fY for both round rects but it
+ // makes the shader code simpler.
+ pdman.set4f(fRadiiUni,
+ 0.5f * first.getSimpleRadii().fX,
+ 0.5f * first.getSimpleRadii().fY,
+ 0.5f * second.getSimpleRadii().fX,
+ 0.5f * second.getSimpleRadii().fY);
+ }
pdman.set2f(fPadRadUni, edgeFP.pad(), edgeFP.radius());
}