| 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();
|
|
|