Index: src/gpu/effects/GrOvalEffect.cpp |
diff --git a/src/gpu/effects/GrOvalEffect.cpp b/src/gpu/effects/GrOvalEffect.cpp |
index 4532ddfd3c4f1a1da3213a283f208cd1b3aaa362..c7e685f9022a9077eaf0e8278e7322017b243eaf 100644 |
--- a/src/gpu/effects/GrOvalEffect.cpp |
+++ b/src/gpu/effects/GrOvalEffect.cpp |
@@ -133,19 +133,19 @@ void GLCircleEffect::emitCode(EmitArgs& args) { |
// mediump. It'd be nice to only to this on mediump devices but we currently don't have the |
// caps here. |
if (GrProcessorEdgeTypeIsInverseFill(ce.getEdgeType())) { |
- fragBuilder->codeAppendf("\t\tfloat d = (length((%s.xy - %s.xy) * %s.w) - 1.0) * %s.z;\n", |
+ fragBuilder->codeAppendf("float d = (length((%s.xy - %s.xy) * %s.w) - 1.0) * %s.z;", |
circleName, fragmentPos, circleName, circleName); |
} else { |
- fragBuilder->codeAppendf("\t\tfloat d = (1.0 - length((%s.xy - %s.xy) * %s.w)) * %s.z;\n", |
+ fragBuilder->codeAppendf("float d = (1.0 - length((%s.xy - %s.xy) * %s.w)) * %s.z;", |
circleName, fragmentPos, circleName, circleName); |
} |
if (GrProcessorEdgeTypeIsAA(ce.getEdgeType())) { |
- fragBuilder->codeAppend("\t\td = clamp(d, 0.0, 1.0);\n"); |
+ fragBuilder->codeAppend("d = clamp(d, 0.0, 1.0);"); |
} else { |
- fragBuilder->codeAppend("\t\td = d > 0.5 ? 1.0 : 0.0;\n"); |
+ fragBuilder->codeAppend("d = d > 0.5 ? 1.0 : 0.0;"); |
} |
- fragBuilder->codeAppendf("\t\t%s = %s;\n", args.fOutputColor, |
+ fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, |
(GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("d")).c_str()); |
} |
@@ -276,6 +276,7 @@ protected: |
private: |
GrGLSLProgramDataManager::UniformHandle fEllipseUniform; |
+ GrGLSLProgramDataManager::UniformHandle fScaleUniform; |
SkPoint fPrevCenter; |
SkVector fPrevRadii; |
@@ -295,39 +296,55 @@ void GLEllipseEffect::emitCode(EmitArgs& args) { |
kVec4f_GrSLType, kHigh_GrSLPrecision, |
"ellipse", |
&ellipseName); |
+ // If we're on a device with a "real" mediump then we'll do the distance computation in a space |
+ // that is normalized by the larger radius. The scale uniform will be scale, 1/scale. The |
+ // inverse squared radii uniform values are already in this normalized space. The center is |
+ // not. |
+ const char* scaleName = nullptr; |
+ if (args.fGLSLCaps->floatPrecisionVaries()) { |
+ fScaleUniform = args.fUniformHandler->addUniform( |
+ GrGLSLUniformHandler::kFragment_Visibility, kVec2f_GrSLType, kDefault_GrSLPrecision, |
+ "scale", &scaleName); |
+ } |
GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; |
const char* fragmentPos = fragBuilder->fragmentPosition(); |
// d is the offset to the ellipse center |
- fragBuilder->codeAppendf("\t\tvec2 d = %s.xy - %s.xy;\n", fragmentPos, ellipseName); |
- fragBuilder->codeAppendf("\t\tvec2 Z = d * %s.zw;\n", ellipseName); |
+ fragBuilder->codeAppendf("vec2 d = %s.xy - %s.xy;", fragmentPos, ellipseName); |
+ if (scaleName) { |
+ fragBuilder->codeAppendf("d *= %s.y;", scaleName); |
+ } |
+ fragBuilder->codeAppendf("vec2 Z = d * %s.zw;", ellipseName); |
// implicit is the evaluation of (x/rx)^2 + (y/ry)^2 - 1. |
- fragBuilder->codeAppend("\t\tfloat implicit = dot(Z, d) - 1.0;\n"); |
+ fragBuilder->codeAppend("float implicit = dot(Z, d) - 1.0;"); |
// grad_dot is the squared length of the gradient of the implicit. |
- fragBuilder->codeAppendf("\t\tfloat grad_dot = 4.0 * dot(Z, Z);\n"); |
- // avoid calling inversesqrt on zero. |
- fragBuilder->codeAppend("\t\tgrad_dot = max(grad_dot, 1.0e-4);\n"); |
- fragBuilder->codeAppendf("\t\tfloat approx_dist = implicit * inversesqrt(grad_dot);\n"); |
+ fragBuilder->codeAppendf("float grad_dot = 4.0 * dot(Z, Z);"); |
+ // Avoid calling inversesqrt on zero. |
+ fragBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);"); |
+ fragBuilder->codeAppendf("float approx_dist = implicit * inversesqrt(grad_dot);"); |
+ if (scaleName) { |
+ fragBuilder->codeAppendf("approx_dist *= %s.x;", scaleName); |
+ } |
switch (ee.getEdgeType()) { |
case kFillAA_GrProcessorEdgeType: |
- fragBuilder->codeAppend("\t\tfloat alpha = clamp(0.5 - approx_dist, 0.0, 1.0);\n"); |
+ fragBuilder->codeAppend("float alpha = clamp(0.5 - approx_dist, 0.0, 1.0);"); |
break; |
case kInverseFillAA_GrProcessorEdgeType: |
- fragBuilder->codeAppend("\t\tfloat alpha = clamp(0.5 + approx_dist, 0.0, 1.0);\n"); |
+ fragBuilder->codeAppend("float alpha = clamp(0.5 + approx_dist, 0.0, 1.0);"); |
break; |
case kFillBW_GrProcessorEdgeType: |
- fragBuilder->codeAppend("\t\tfloat alpha = approx_dist > 0.0 ? 0.0 : 1.0;\n"); |
+ fragBuilder->codeAppend("float alpha = approx_dist > 0.0 ? 0.0 : 1.0;"); |
break; |
case kInverseFillBW_GrProcessorEdgeType: |
- fragBuilder->codeAppend("\t\tfloat alpha = approx_dist > 0.0 ? 1.0 : 0.0;\n"); |
+ fragBuilder->codeAppend("float alpha = approx_dist > 0.0 ? 1.0 : 0.0;"); |
break; |
case kHairlineAA_GrProcessorEdgeType: |
SkFAIL("Hairline not expected here."); |
} |
- fragBuilder->codeAppendf("\t\t%s = %s;\n", args.fOutputColor, |
+ fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, |
(GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha")).c_str()); |
} |
@@ -341,8 +358,26 @@ void GLEllipseEffect::onSetData(const GrGLSLProgramDataManager& pdman, |
const GrProcessor& effect) { |
const EllipseEffect& ee = effect.cast<EllipseEffect>(); |
if (ee.getRadii() != fPrevRadii || ee.getCenter() != fPrevCenter) { |
- SkScalar invRXSqd = 1.f / (ee.getRadii().fX * ee.getRadii().fX); |
- SkScalar invRYSqd = 1.f / (ee.getRadii().fY * ee.getRadii().fY); |
+ float invRXSqd; |
+ float invRYSqd; |
+ // If we're using a scale factor to work around precision issues, choose the larger radius |
+ // as the scale factor. The inv radii need to be pre-adjusted by the scale factor. |
+ if (fScaleUniform.isValid()) { |
+ if (ee.getRadii().fX > ee.getRadii().fY) { |
+ invRXSqd = 1.f; |
+ invRYSqd = (ee.getRadii().fX * ee.getRadii().fX) / |
+ (ee.getRadii().fY * ee.getRadii().fY); |
+ pdman.set2f(fScaleUniform, ee.getRadii().fX, 1.f / ee.getRadii().fX); |
+ } else { |
+ invRXSqd = (ee.getRadii().fY * ee.getRadii().fY) / |
+ (ee.getRadii().fX * ee.getRadii().fX); |
+ invRYSqd = 1.f; |
+ pdman.set2f(fScaleUniform, ee.getRadii().fY, 1.f / ee.getRadii().fY); |
+ } |
+ } else { |
+ invRXSqd = 1.f / (ee.getRadii().fX * ee.getRadii().fX); |
+ invRYSqd = 1.f / (ee.getRadii().fY * ee.getRadii().fY); |
+ } |
pdman.set4f(fEllipseUniform, ee.getCenter().fX, ee.getCenter().fY, invRXSqd, invRYSqd); |
fPrevCenter = ee.getCenter(); |
fPrevRadii = ee.getRadii(); |