void GrGLConvexPolyEffect::emitCode(EmitArgs& args) { const GrConvexPolyEffect& cpe = args.fFp.cast<GrConvexPolyEffect>(); const char *edgeArrayName; fEdgeUniform = args.fUniformHandler->addUniformArray(GrGLSLUniformHandler::kFragment_Visibility, kVec3f_GrSLType, kDefault_GrSLPrecision, "edges", cpe.getEdgeCount(), &edgeArrayName); GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; fragBuilder->codeAppend("\t\tfloat alpha = 1.0;\n"); fragBuilder->codeAppend("\t\tfloat edge;\n"); const char* fragmentPos = fragBuilder->fragmentPosition(); for (int i = 0; i < cpe.getEdgeCount(); ++i) { fragBuilder->codeAppendf("\t\tedge = dot(%s[%d], vec3(%s.x, %s.y, 1));\n", edgeArrayName, i, fragmentPos, fragmentPos); if (GrProcessorEdgeTypeIsAA(cpe.getEdgeType())) { fragBuilder->codeAppend("\t\tedge = clamp(edge, 0.0, 1.0);\n"); } else { fragBuilder->codeAppend("\t\tedge = edge >= 0.5 ? 1.0 : 0.0;\n"); } fragBuilder->codeAppend("\t\talpha *= edge;\n"); } if (GrProcessorEdgeTypeIsInverseFill(cpe.getEdgeType())) { fragBuilder->codeAppend("\talpha = 1.0 - alpha;\n"); } fragBuilder->codeAppendf("\t%s = %s;\n", args.fOutputColor, (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha")).c_str()); }
void GrGLCircleBlurFragmentProcessor::emitCode(EmitArgs& args) { const char *dataName; // The data is formatted as: // x,y - the center of the circle // z - the distance at which the intensity starts falling off (e.g., the start of the table) // w - the size of the profile texture fDataUniform = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, kVec4f_GrSLType, kDefault_GrSLPrecision, "data", &dataName); GrGLSLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder(); const char *fragmentPos = fsBuilder->fragmentPosition(); if (args.fInputColor) { fsBuilder->codeAppendf("vec4 src=%s;", args.fInputColor); } else { fsBuilder->codeAppendf("vec4 src=vec4(1);"); } fsBuilder->codeAppendf("vec2 vec = %s.xy - %s.xy;", fragmentPos, dataName); fsBuilder->codeAppendf("float dist = (length(vec) - %s.z + 0.5) / %s.w;", dataName, dataName); fsBuilder->codeAppendf("float intensity = "); fsBuilder->appendTextureLookup(args.fSamplers[0], "vec2(dist, 0.5)"); fsBuilder->codeAppend(".a;"); fsBuilder->codeAppendf("%s = src * intensity;\n", args.fOutputColor ); }
void GLDitherEffect::emitCode(EmitArgs& args) { GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; // Generate a random number based on the fragment position. For this // random number generator, we use the "GLSL rand" function // that seems to be floating around on the internet. It works under // the assumption that sin(<big number>) oscillates with high frequency // and sampling it will generate "randomness". Since we're using this // for rendering and not cryptography it should be OK. // For each channel c, add the random offset to the pixel to either bump // it up or let it remain constant during quantization. fragBuilder->codeAppendf("\t\tfloat r = " "fract(sin(dot(%s.xy ,vec2(12.9898,78.233))) * 43758.5453);\n", fragBuilder->fragmentPosition()); fragBuilder->codeAppendf("\t\t%s = (1.0/255.0) * vec4(r, r, r, r) + %s;\n", args.fOutputColor, GrGLSLExpr4(args.fInputColor).c_str()); }
void GLAARectEffect::emitCode(EmitArgs& args) { const AARectEffect& aare = args.fFp.cast<AARectEffect>(); const char *rectName; // The rect uniform's xyzw refer to (left + 0.5, top + 0.5, right - 0.5, bottom - 0.5), // respectively. fRectUniform = args.fUniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, kVec4f_GrSLType, kDefault_GrSLPrecision, "rect", &rectName); GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; const char* fragmentPos = fragBuilder->fragmentPosition(); if (GrProcessorEdgeTypeIsAA(aare.getEdgeType())) { // The amount of coverage removed in x and y by the edges is computed as a pair of negative // numbers, xSub and ySub. fragBuilder->codeAppend("\t\tfloat xSub, ySub;\n"); fragBuilder->codeAppendf("\t\txSub = min(%s.x - %s.x, 0.0);\n", fragmentPos, rectName); fragBuilder->codeAppendf("\t\txSub += min(%s.z - %s.x, 0.0);\n", rectName, fragmentPos); fragBuilder->codeAppendf("\t\tySub = min(%s.y - %s.y, 0.0);\n", fragmentPos, rectName); fragBuilder->codeAppendf("\t\tySub += min(%s.w - %s.y, 0.0);\n", rectName, fragmentPos); // Now compute coverage in x and y and multiply them to get the fraction of the pixel // covered. fragBuilder->codeAppendf("\t\tfloat alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));\n"); } else { fragBuilder->codeAppendf("\t\tfloat alpha = 1.0;\n"); fragBuilder->codeAppendf("\t\talpha *= (%s.x - %s.x) > -0.5 ? 1.0 : 0.0;\n", fragmentPos, rectName); fragBuilder->codeAppendf("\t\talpha *= (%s.z - %s.x) > -0.5 ? 1.0 : 0.0;\n", rectName, fragmentPos); fragBuilder->codeAppendf("\t\talpha *= (%s.y - %s.y) > -0.5 ? 1.0 : 0.0;\n", fragmentPos, rectName); fragBuilder->codeAppendf("\t\talpha *= (%s.w - %s.y) > -0.5 ? 1.0 : 0.0;\n", rectName, fragmentPos); } if (GrProcessorEdgeTypeIsInverseFill(aare.getEdgeType())) { fragBuilder->codeAppend("\t\talpha = 1.0 - alpha;\n"); } fragBuilder->codeAppendf("\t\t%s = %s;\n", args.fOutputColor, (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha")).c_str()); }
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { const PLSQuadEdgeEffect& qe = args.fGP.cast<PLSQuadEdgeEffect>(); GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; // emit attributes varyingHandler->emitAttributes(qe); GrGLSLVertToFrag uv(kVec2f_GrSLType); varyingHandler->addVarying("uv", &uv, kHigh_GrSLPrecision); vsBuilder->codeAppendf("%s = %s;", uv.vsOut(), qe.inUV()->fName); GrGLSLVertToFrag ep1(kVec2f_GrSLType); varyingHandler->addVarying("endpoint1", &ep1, kHigh_GrSLPrecision); vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", ep1.vsOut(), qe.inEndpoint1()->fName, qe.inEndpoint1()->fName); GrGLSLVertToFrag ep2(kVec2f_GrSLType); varyingHandler->addVarying("endpoint2", &ep2, kHigh_GrSLPrecision); vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", ep2.vsOut(), qe.inEndpoint2()->fName, qe.inEndpoint2()->fName); GrGLSLVertToFrag delta(kVec2f_GrSLType); varyingHandler->addVarying("delta", &delta, kHigh_GrSLPrecision); vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;", delta.vsOut(), ep1.vsOut(), ep2.vsOut(), ep2.vsOut(), ep1.vsOut()); GrGLSLVertToFrag windings(kInt_GrSLType); varyingHandler->addFlatVarying("windings", &windings, kLow_GrSLPrecision); vsBuilder->codeAppendf("%s = %s;", windings.vsOut(), qe.inWindings()->fName); // Setup position this->setupPosition(vsBuilder, gpArgs, qe.inPosition()->fName); // emit transforms this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar, qe.inPosition()->fName, qe.localMatrix(), args.fTransformsIn, args.fTransformsOut); GrGLSLFragmentBuilder* fsBuilder = args.fFragBuilder; SkAssertResult(fsBuilder->enableFeature( GrGLSLFragmentShaderBuilder::kPixelLocalStorage_GLSLFeature)); SkAssertResult(fsBuilder->enableFeature( GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); static const int QUAD_ARGS = 2; GrGLSLShaderVar inQuadArgs[QUAD_ARGS] = { GrGLSLShaderVar("dot", kFloat_GrSLType, 0, kHigh_GrSLPrecision), GrGLSLShaderVar("uv", kVec2f_GrSLType, 0, kHigh_GrSLPrecision) }; SkString inQuadName; const char* inQuadCode = "if (uv.x * uv.x <= uv.y) {" "return dot >= 0.0;" "} else {" "return false;" "}"; fsBuilder->emitFunction(kBool_GrSLType, "in_quad", QUAD_ARGS, inQuadArgs, inQuadCode, &inQuadName); fsBuilder->declAppendf(GR_GL_PLS_PATH_DATA_DECL); // keep the derivative instructions outside the conditional fsBuilder->codeAppendf("highp vec2 uvdX = dFdx(%s);", uv.fsIn()); fsBuilder->codeAppendf("highp vec2 uvdY = dFdy(%s);", uv.fsIn()); fsBuilder->codeAppend("highp vec2 uvIncX = uvdX * 0.45 + uvdY * -0.1;"); fsBuilder->codeAppend("highp vec2 uvIncY = uvdX * 0.1 + uvdY * 0.55;"); fsBuilder->codeAppendf("highp vec2 uv = %s.xy - uvdX * 0.35 - uvdY * 0.25;", uv.fsIn()); fsBuilder->codeAppendf("highp vec2 firstSample = %s.xy - vec2(0.25);", fsBuilder->fragmentPosition()); fsBuilder->codeAppendf("highp float d = dot(%s, (firstSample - %s).yx) * 2.0;", delta.fsIn(), ep1.fsIn()); fsBuilder->codeAppendf("pls.windings[0] += %s(d, uv) ? %s : 0;", inQuadName.c_str(), windings.fsIn()); fsBuilder->codeAppend("uv += uvIncX;"); fsBuilder->codeAppendf("d += %s.x;", delta.fsIn()); fsBuilder->codeAppendf("pls.windings[1] += %s(d, uv) ? %s : 0;", inQuadName.c_str(), windings.fsIn()); fsBuilder->codeAppend("uv += uvIncY;"); fsBuilder->codeAppendf("d += %s.y;", delta.fsIn()); fsBuilder->codeAppendf("pls.windings[2] += %s(d, uv) ? %s : 0;", inQuadName.c_str(), windings.fsIn()); fsBuilder->codeAppend("uv -= uvIncX;"); fsBuilder->codeAppendf("d -= %s.x;", delta.fsIn()); fsBuilder->codeAppendf("pls.windings[3] += %s(d, uv) ? %s : 0;", inQuadName.c_str(), windings.fsIn()); }
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { const PLSAATriangleEffect& te = args.fGP.cast<PLSAATriangleEffect>(); GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; varyingHandler->emitAttributes(te); this->setupPosition(vsBuilder, gpArgs, te.inPosition()->fName); GrGLSLVertToFrag v1(kVec2f_GrSLType); varyingHandler->addVarying("Vertex1", &v1, kHigh_GrSLPrecision); vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", v1.vsOut(), te.inVertex1()->fName, te.inVertex1()->fName); GrGLSLVertToFrag v2(kVec2f_GrSLType); varyingHandler->addVarying("Vertex2", &v2, kHigh_GrSLPrecision); vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", v2.vsOut(), te.inVertex2()->fName, te.inVertex2()->fName); GrGLSLVertToFrag v3(kVec2f_GrSLType); varyingHandler->addVarying("Vertex3", &v3, kHigh_GrSLPrecision); vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", v3.vsOut(), te.inVertex3()->fName, te.inVertex3()->fName); GrGLSLVertToFrag delta1(kVec2f_GrSLType); varyingHandler->addVarying("delta1", &delta1, kHigh_GrSLPrecision); vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;", delta1.vsOut(), v1.vsOut(), v2.vsOut(), v2.vsOut(), v1.vsOut()); GrGLSLVertToFrag delta2(kVec2f_GrSLType); varyingHandler->addVarying("delta2", &delta2, kHigh_GrSLPrecision); vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;", delta2.vsOut(), v2.vsOut(), v3.vsOut(), v3.vsOut(), v2.vsOut()); GrGLSLVertToFrag delta3(kVec2f_GrSLType); varyingHandler->addVarying("delta3", &delta3, kHigh_GrSLPrecision); vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;", delta3.vsOut(), v3.vsOut(), v1.vsOut(), v1.vsOut(), v3.vsOut()); GrGLSLVertToFrag windings(kInt_GrSLType); varyingHandler->addFlatVarying("windings", &windings, kLow_GrSLPrecision); vsBuilder->codeAppendf("%s = %s;", windings.vsOut(), te.inWindings()->fName); // emit transforms this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar, te.inPosition()->fName, te.localMatrix(), args.fTransformsIn, args.fTransformsOut); GrGLSLFragmentBuilder* fsBuilder = args.fFragBuilder; SkAssertResult(fsBuilder->enableFeature( GrGLSLFragmentShaderBuilder::kPixelLocalStorage_GLSLFeature)); SkAssertResult(fsBuilder->enableFeature( GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); fsBuilder->declAppendf(GR_GL_PLS_PATH_DATA_DECL); // Compute four subsamples, each shifted a quarter pixel along x and y from // gl_FragCoord. The oriented box positioning of the subsamples is of course not // optimal, but it greatly simplifies the math and this simplification is necessary for // performance reasons. fsBuilder->codeAppendf("highp vec2 firstSample = %s.xy - vec2(0.25);", fsBuilder->fragmentPosition()); fsBuilder->codeAppendf("highp vec2 delta1 = %s;", delta1.fsIn()); fsBuilder->codeAppendf("highp vec2 delta2 = %s;", delta2.fsIn()); fsBuilder->codeAppendf("highp vec2 delta3 = %s;", delta3.fsIn()); // Check whether first sample is inside the triangle by computing three dot products. If // all are < 0, we're inside. The first vector in each case is half of what it is // "supposed" to be, because we re-use them later as adjustment factors for which half // is the correct value, so we multiply the dots by two to compensate. fsBuilder->codeAppendf("highp float d1 = dot(delta1, (firstSample - %s).yx) * 2.0;", v1.fsIn()); fsBuilder->codeAppendf("highp float d2 = dot(delta2, (firstSample - %s).yx) * 2.0;", v2.fsIn()); fsBuilder->codeAppendf("highp float d3 = dot(delta3, (firstSample - %s).yx) * 2.0;", v3.fsIn()); fsBuilder->codeAppend("highp float dmax = max(d1, max(d2, d3));"); fsBuilder->codeAppendf("pls.windings[0] += (dmax <= 0.0) ? %s : 0;", windings.fsIn()); // for subsequent samples, we don't recalculate the entire dot product -- just adjust it // to the value it would have if we did recompute it. fsBuilder->codeAppend("d1 += delta1.x;"); fsBuilder->codeAppend("d2 += delta2.x;"); fsBuilder->codeAppend("d3 += delta3.x;"); fsBuilder->codeAppend("dmax = max(d1, max(d2, d3));"); fsBuilder->codeAppendf("pls.windings[1] += (dmax <= 0.0) ? %s : 0;", windings.fsIn()); fsBuilder->codeAppend("d1 += delta1.y;"); fsBuilder->codeAppend("d2 += delta2.y;"); fsBuilder->codeAppend("d3 += delta3.y;"); fsBuilder->codeAppend("dmax = max(d1, max(d2, d3));"); fsBuilder->codeAppendf("pls.windings[2] += (dmax <= 0.0) ? %s : 0;", windings.fsIn()); fsBuilder->codeAppend("d1 -= delta1.x;"); fsBuilder->codeAppend("d2 -= delta2.x;"); fsBuilder->codeAppend("d3 -= delta3.x;"); fsBuilder->codeAppend("dmax = max(d1, max(d2, d3));"); fsBuilder->codeAppendf("pls.windings[3] += (dmax <= 0.0) ? %s : 0;", windings.fsIn()); }
void GLEllipticalRRectEffect::emitCode(EmitArgs& args) { const EllipticalRRectEffect& erre = args.fFp.cast<EllipticalRRectEffect>(); const char *rectName; // The inner rect is the rrect bounds inset by the x/y radii fInnerRectUniform = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, kVec4f_GrSLType, kDefault_GrSLPrecision, "innerRect", &rectName); GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; const char* fragmentPos = fragBuilder->fragmentPosition(); // At each quarter-ellipse corner we compute a vector that is the offset of the fragment pos // to the ellipse center. The vector is pinned in x and y to be in the quarter-plane relevant // to that corner. This means that points near the interior near the rrect top edge will have // a vector that points straight up for both the TL left and TR corners. Computing an // alpha from this vector at either the TR or TL corner will give the correct result. Similarly, // fragments near the other three edges will get the correct AA. Fragments in the interior of // the rrect will have a (0,0) vector at all four corners. So long as the radii > 0.5 they will // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas. // // 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); // The uniforms with the inv squared radii are highp to prevent underflow. switch (erre.getRRect().getType()) { case SkRRect::kSimple_Type: { const char *invRadiiXYSqdName; fInvRadiiSqdUniform = args.fBuilder->addUniform( GrGLSLProgramBuilder::kFragment_Visibility, kVec2f_GrSLType, kHigh_GrSLPrecision, "invRadiiXY", &invRadiiXYSqdName); fragBuilder->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n"); // Z is the x/y offsets divided by squared radii. fragBuilder->codeAppendf("\t\tvec2 Z = dxy * %s;\n", invRadiiXYSqdName); break; } case SkRRect::kNinePatch_Type: { const char *invRadiiLTRBSqdName; fInvRadiiSqdUniform = args.fBuilder->addUniform( GrGLSLProgramBuilder::kFragment_Visibility, kVec4f_GrSLType, kHigh_GrSLPrecision, "invRadiiLTRB", &invRadiiLTRBSqdName); fragBuilder->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n"); // 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", 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"); // 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"); if (kFillAA_GrProcessorEdgeType == erre.getEdgeType()) { fragBuilder->codeAppend("\t\tfloat alpha = clamp(0.5 - approx_dist, 0.0, 1.0);\n"); } else { fragBuilder->codeAppend("\t\tfloat alpha = clamp(0.5 + approx_dist, 0.0, 1.0);\n"); } fragBuilder->codeAppendf("\t\t%s = %s;\n", args.fOutputColor, (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha")).c_str()); }
void GLCircularRRectEffect::emitCode(EmitArgs& args) { const CircularRRectEffect& crre = args.fFp.cast<CircularRRectEffect>(); const char *rectName; const char *radiusPlusHalfName; // The inner rect is the rrect bounds inset by the radius. Its left, top, right, and bottom // edges correspond to components x, y, z, and w, respectively. When a side of the rrect has // only rectangular corners, that side's value corresponds to the rect edge's value outset by // half a pixel. fInnerRectUniform = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, kVec4f_GrSLType, kDefault_GrSLPrecision, "innerRect", &rectName); fRadiusPlusHalfUniform = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, kFloat_GrSLType, kDefault_GrSLPrecision, "radiusPlusHalf", &radiusPlusHalfName); GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; const char* fragmentPos = fragBuilder->fragmentPosition(); // At each quarter-circle corner we compute a vector that is the offset of the fragment position // from the circle center. The vector is pinned in x and y to be in the quarter-plane relevant // to that corner. This means that points near the interior near the rrect top edge will have // a vector that points straight up for both the TL left and TR corners. Computing an // alpha from this vector at either the TR or TL corner will give the correct result. Similarly, // fragments near the other three edges will get the correct AA. Fragments in the interior of // the rrect will have a (0,0) vector at all four corners. So long as the radius > 0.5 they will // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas. // 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. // // For the cases where one half of the rrect is rectangular we drop one of the x or y // computations, compute a separate rect edge alpha for the rect side, and mul the two computed // alphas together. switch (crre.getCircularCornerFlags()) { case CircularRRectEffect::kAll_CornerFlags: 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->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n"); fragBuilder->codeAppendf("\t\tfloat alpha = clamp(%s - length(dxy), 0.0, 1.0);\n", radiusPlusHalfName); break; case CircularRRectEffect::kTopLeft_CornerFlag: fragBuilder->codeAppendf("\t\tvec2 dxy = max(%s.xy - %s.xy, 0.0);\n", rectName, fragmentPos); fragBuilder->codeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n", rectName, fragmentPos); fragBuilder->codeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n", rectName, fragmentPos); fragBuilder->codeAppendf( "\t\tfloat alpha = bottomAlpha * rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", radiusPlusHalfName); break; case CircularRRectEffect::kTopRight_CornerFlag: fragBuilder->codeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.z, %s.y - %s.y), 0.0);\n", fragmentPos, rectName, rectName, fragmentPos); fragBuilder->codeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n", fragmentPos, rectName); fragBuilder->codeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n", rectName, fragmentPos); fragBuilder->codeAppendf( "\t\tfloat alpha = bottomAlpha * leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", radiusPlusHalfName); break; case CircularRRectEffect::kBottomRight_CornerFlag: fragBuilder->codeAppendf("\t\tvec2 dxy = max(%s.xy - %s.zw, 0.0);\n", fragmentPos, rectName); fragBuilder->codeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n", fragmentPos, rectName); fragBuilder->codeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n", fragmentPos, rectName); fragBuilder->codeAppendf( "\t\tfloat alpha = topAlpha * leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", radiusPlusHalfName); break; case CircularRRectEffect::kBottomLeft_CornerFlag: fragBuilder->codeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.x, %s.y - %s.w), 0.0);\n", rectName, fragmentPos, fragmentPos, rectName); fragBuilder->codeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n", rectName, fragmentPos); fragBuilder->codeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n", fragmentPos, rectName); fragBuilder->codeAppendf( "\t\tfloat alpha = topAlpha * rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", radiusPlusHalfName); break; case CircularRRectEffect::kLeft_CornerFlags: fragBuilder->codeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos); fragBuilder->codeAppendf("\t\tfloat dy1 = %s.y - %s.w;\n", fragmentPos, rectName); fragBuilder->codeAppend("\t\tvec2 dxy = max(vec2(dxy0.x, max(dxy0.y, dy1)), 0.0);\n"); fragBuilder->codeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n", rectName, fragmentPos); fragBuilder->codeAppendf( "\t\tfloat alpha = rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", radiusPlusHalfName); break; case CircularRRectEffect::kTop_CornerFlags: fragBuilder->codeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos); fragBuilder->codeAppendf("\t\tfloat dx1 = %s.x - %s.z;\n", fragmentPos, rectName); fragBuilder->codeAppend("\t\tvec2 dxy = max(vec2(max(dxy0.x, dx1), dxy0.y), 0.0);\n"); fragBuilder->codeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n", rectName, fragmentPos); fragBuilder->codeAppendf( "\t\tfloat alpha = bottomAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", radiusPlusHalfName); break; case CircularRRectEffect::kRight_CornerFlags: fragBuilder->codeAppendf("\t\tfloat dy0 = %s.y - %s.y;\n", rectName, fragmentPos); fragBuilder->codeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName); fragBuilder->codeAppend("\t\tvec2 dxy = max(vec2(dxy1.x, max(dy0, dxy1.y)), 0.0);\n"); fragBuilder->codeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n", fragmentPos, rectName); fragBuilder->codeAppendf( "\t\tfloat alpha = leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", radiusPlusHalfName); break; case CircularRRectEffect::kBottom_CornerFlags: fragBuilder->codeAppendf("\t\tfloat dx0 = %s.x - %s.x;\n", rectName, fragmentPos); fragBuilder->codeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName); fragBuilder->codeAppend("\t\tvec2 dxy = max(vec2(max(dx0, dxy1.x), dxy1.y), 0.0);\n"); fragBuilder->codeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n", fragmentPos, rectName); fragBuilder->codeAppendf( "\t\tfloat alpha = topAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n", radiusPlusHalfName); break; } if (kInverseFillAA_GrProcessorEdgeType == crre.getEdgeType()) { fragBuilder->codeAppend("\t\talpha = 1.0 - alpha;\n"); } fragBuilder->codeAppendf("\t\t%s = %s;\n", args.fOutputColor, (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha")).c_str()); }