| Index: src/gpu/effects/GrRRectEffect.cpp
|
| diff --git a/src/gpu/effects/GrRRectEffect.cpp b/src/gpu/effects/GrRRectEffect.cpp
|
| index 0b758759e869affb9aa123679545da739fdebdac..0b492762c2ca8777393336b4ca6ae1a21be0eb74 100644
|
| --- a/src/gpu/effects/GrRRectEffect.cpp
|
| +++ b/src/gpu/effects/GrRRectEffect.cpp
|
| @@ -498,7 +498,8 @@ protected:
|
| private:
|
| GrGLSLProgramDataManager::UniformHandle fInnerRectUniform;
|
| GrGLSLProgramDataManager::UniformHandle fInvRadiiSqdUniform;
|
| - SkRRect fPrevRRect;
|
| + GrGLSLProgramDataManager::UniformHandle fScaleUniform;
|
| + SkRRect fPrevRRect;
|
| typedef GrGLSLFragmentProcessor INHERITED;
|
| };
|
|
|
| @@ -530,55 +531,77 @@ void GLEllipticalRRectEffect::emitCode(EmitArgs& args) {
|
| // The code below is a simplified version of the above that performs maxs on the vector
|
| // components before computing distances and alpha values so that only one distance computation
|
| // need be computed to determine the min alpha.
|
| - fragBuilder->codeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
|
| - fragBuilder->codeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
|
| + fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - %s.xy;", rectName, fragmentPos);
|
| + fragBuilder->codeAppendf("vec2 dxy1 = %s.xy - %s.zw;", fragmentPos, rectName);
|
| +
|
| + // 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 largest radius. The scale uniform will be scale, 1/scale. The
|
| + // radii uniform values are already in this normalized space.
|
| + const char* scaleName = nullptr;
|
| + if (args.fGLSLCaps->floatPrecisionVaries()) {
|
| + fScaleUniform = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
|
| + kVec2f_GrSLType, kDefault_GrSLPrecision,
|
| + "scale", &scaleName);
|
| + }
|
| +
|
| // The uniforms with the inv squared radii are highp to prevent underflow.
|
| switch (erre.getRRect().getType()) {
|
| case SkRRect::kSimple_Type: {
|
| const char *invRadiiXYSqdName;
|
| fInvRadiiSqdUniform = uniformHandler->addUniform(
|
| GrGLSLUniformHandler::kFragment_Visibility,
|
| - kVec2f_GrSLType, kHigh_GrSLPrecision,
|
| + kVec2f_GrSLType, kDefault_GrSLPrecision,
|
| "invRadiiXY",
|
| &invRadiiXYSqdName);
|
| - fragBuilder->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
|
| + fragBuilder->codeAppend("vec2 dxy = max(max(dxy0, dxy1), 0.0);");
|
| + if (scaleName) {
|
| + fragBuilder->codeAppendf("dxy *= %s.y;", scaleName);
|
| + }
|
| // Z is the x/y offsets divided by squared radii.
|
| - fragBuilder->codeAppendf("\t\tvec2 Z = dxy * %s;\n", invRadiiXYSqdName);
|
| + fragBuilder->codeAppendf("vec2 Z = dxy * %s.xy;", invRadiiXYSqdName);
|
| break;
|
| }
|
| case SkRRect::kNinePatch_Type: {
|
| const char *invRadiiLTRBSqdName;
|
| fInvRadiiSqdUniform = uniformHandler->addUniform(
|
| GrGLSLUniformHandler::kFragment_Visibility,
|
| - kVec4f_GrSLType, kHigh_GrSLPrecision,
|
| + kVec4f_GrSLType, kDefault_GrSLPrecision,
|
| "invRadiiLTRB",
|
| &invRadiiLTRBSqdName);
|
| - fragBuilder->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
|
| + if (scaleName) {
|
| + fragBuilder->codeAppendf("dxy0 *= %s.y;", scaleName);
|
| + fragBuilder->codeAppendf("dxy1 *= %s.y;", scaleName);
|
| + }
|
| + fragBuilder->codeAppend("vec2 dxy = max(max(dxy0, dxy1), 0.0);");
|
| // Z is the x/y offsets divided by squared radii. We only care about the (at most) one
|
| // corner where both the x and y offsets are positive, hence the maxes. (The inverse
|
| // squared radii will always be positive.)
|
| - fragBuilder->codeAppendf("\t\tvec2 Z = max(max(dxy0 * %s.xy, dxy1 * %s.zw), 0.0);\n",
|
| + fragBuilder->codeAppendf("vec2 Z = max(max(dxy0 * %s.xy, dxy1 * %s.zw), 0.0);",
|
| invRadiiLTRBSqdName, invRadiiLTRBSqdName);
|
| +
|
| break;
|
| }
|
| default:
|
| SkFAIL("RRect should always be simple or nine-patch.");
|
| }
|
| // implicit is the evaluation of (x/a)^2 + (y/b)^2 - 1.
|
| - fragBuilder->codeAppend("\t\tfloat implicit = dot(Z, dxy) - 1.0;\n");
|
| + fragBuilder->codeAppend("float implicit = dot(Z, dxy) - 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");
|
| + fragBuilder->codeAppend("float grad_dot = 4.0 * dot(Z, Z);");
|
| // 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->codeAppend("grad_dot = max(grad_dot, 1.0e-4);");
|
| + fragBuilder->codeAppend("float approx_dist = implicit * inversesqrt(grad_dot);");
|
| + if (scaleName) {
|
| + fragBuilder->codeAppendf("approx_dist *= %s.x;", scaleName);
|
| + }
|
|
|
| if (kFillAA_GrProcessorEdgeType == erre.getEdgeType()) {
|
| - 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);");
|
| } else {
|
| - 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);");
|
| }
|
|
|
| - fragBuilder->codeAppendf("\t\t%s = %s;\n", args.fOutputColor,
|
| + fragBuilder->codeAppendf("%s = %s;", args.fOutputColor,
|
| (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha")).c_str());
|
| }
|
|
|
| @@ -593,6 +616,8 @@ void GLEllipticalRRectEffect::onSetData(const GrGLSLProgramDataManager& pdman,
|
| const GrProcessor& effect) {
|
| const EllipticalRRectEffect& erre = effect.cast<EllipticalRRectEffect>();
|
| const SkRRect& rrect = erre.getRRect();
|
| + // If we're using a scale factor to work around precision issues, choose the largest radius
|
| + // as the scale factor. The inv radii need to be pre-adjusted by the scale factor.
|
| if (rrect != fPrevRRect) {
|
| SkRect rect = rrect.getBounds();
|
| const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner);
|
| @@ -601,8 +626,18 @@ void GLEllipticalRRectEffect::onSetData(const GrGLSLProgramDataManager& pdman,
|
| switch (erre.getRRect().getType()) {
|
| case SkRRect::kSimple_Type:
|
| rect.inset(r0.fX, r0.fY);
|
| - pdman.set2f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX),
|
| - 1.f / (r0.fY * r0.fY));
|
| + if (fScaleUniform.isValid()) {
|
| + if (r0.fX > r0.fY) {
|
| + pdman.set2f(fInvRadiiSqdUniform, 1.f, (r0.fX * r0.fX) / (r0.fY * r0.fY));
|
| + pdman.set2f(fScaleUniform, r0.fX, 1.f / r0.fX);
|
| + } else {
|
| + pdman.set2f(fInvRadiiSqdUniform, (r0.fY * r0.fY) / (r0.fX * r0.fX), 1.f);
|
| + pdman.set2f(fScaleUniform, r0.fY, 1.f / r0.fY);
|
| + }
|
| + } else {
|
| + pdman.set2f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX),
|
| + 1.f / (r0.fY * r0.fY));
|
| + }
|
| break;
|
| case SkRRect::kNinePatch_Type: {
|
| const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner);
|
| @@ -612,10 +647,20 @@ void GLEllipticalRRectEffect::onSetData(const GrGLSLProgramDataManager& pdman,
|
| rect.fTop += r0.fY;
|
| rect.fRight -= r1.fX;
|
| rect.fBottom -= r1.fY;
|
| - pdman.set4f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX),
|
| - 1.f / (r0.fY * r0.fY),
|
| - 1.f / (r1.fX * r1.fX),
|
| - 1.f / (r1.fY * r1.fY));
|
| + if (fScaleUniform.isValid()) {
|
| + float scale = SkTMax(SkTMax(r0.fX, r0.fY), SkTMax(r1.fX, r1.fY));
|
| + float scaleSqd = scale * scale;
|
| + pdman.set4f(fInvRadiiSqdUniform, scaleSqd / (r0.fX * r0.fX),
|
| + scaleSqd / (r0.fY * r0.fY),
|
| + scaleSqd / (r1.fX * r1.fX),
|
| + scaleSqd / (r1.fY * r1.fY));
|
| + pdman.set2f(fScaleUniform, scale, 1.f / scale);
|
| + } else {
|
| + pdman.set4f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX),
|
| + 1.f / (r0.fY * r0.fY),
|
| + 1.f / (r1.fX * r1.fX),
|
| + 1.f / (r1.fY * r1.fY));
|
| + }
|
| break;
|
| }
|
| default:
|
|
|