void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { const QuadEdgeEffect& qe = args.fGP.cast<QuadEdgeEffect>(); GrGLSLGPBuilder* pb = args.fPB; GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; // emit attributes varyingHandler->emitAttributes(qe); GrGLSLVertToFrag v(kVec4f_GrSLType); varyingHandler->addVarying("QuadEdge", &v); vertBuilder->codeAppendf("%s = %s;", v.vsOut(), qe.inQuadEdge()->fName); GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; // Setup pass through color if (!qe.colorIgnored()) { this->setupUniformColor(pb, fragBuilder, args.fOutputColor, &fColorUniform); } // Setup position this->setupPosition(pb, vertBuilder, gpArgs, qe.inPosition()->fName); // emit transforms this->emitTransforms(args.fPB, vertBuilder, varyingHandler, gpArgs->fPositionVar, qe.inPosition()->fName, qe.localMatrix(), args.fTransformsIn, args.fTransformsOut); SkAssertResult(fragBuilder->enableFeature( GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); fragBuilder->codeAppendf("float edgeAlpha;"); // keep the derivative instructions outside the conditional fragBuilder->codeAppendf("vec2 duvdx = dFdx(%s.xy);", v.fsIn()); fragBuilder->codeAppendf("vec2 duvdy = dFdy(%s.xy);", v.fsIn()); fragBuilder->codeAppendf("if (%s.z > 0.0 && %s.w > 0.0) {", v.fsIn(), v.fsIn()); // today we know z and w are in device space. We could use derivatives fragBuilder->codeAppendf("edgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);", v.fsIn(), v.fsIn()); fragBuilder->codeAppendf ("} else {"); fragBuilder->codeAppendf("vec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y," " 2.0*%s.x*duvdy.x - duvdy.y);", v.fsIn(), v.fsIn()); fragBuilder->codeAppendf("edgeAlpha = (%s.x*%s.x - %s.y);", v.fsIn(), v.fsIn(), v.fsIn()); fragBuilder->codeAppendf("edgeAlpha = " "clamp(0.5 - edgeAlpha / length(gF), 0.0, 1.0);}"); fragBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage); }
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { const PLSFinishEffect& fe = args.fGP.cast<PLSFinishEffect>(); GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; fUseEvenOdd = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType, kLow_GrSLPrecision, "useEvenOdd"); const char* useEvenOdd = uniformHandler->getUniformCStr(fUseEvenOdd); varyingHandler->emitAttributes(fe); this->setupPosition(vsBuilder, gpArgs, fe.inPosition()->fName); this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar, fe.inPosition()->fName, fe.localMatrix(), args.fTransformsIn, args.fTransformsOut); GrGLSLFragmentBuilder* fsBuilder = args.fFragBuilder; SkAssertResult(fsBuilder->enableFeature( GrGLSLFragmentShaderBuilder::kPixelLocalStorage_GLSLFeature)); fsBuilder->declAppendf(GR_GL_PLS_PATH_DATA_DECL); fsBuilder->codeAppend("float coverage;"); fsBuilder->codeAppendf("if (%s != 0.0) {", useEvenOdd); fsBuilder->codeAppend("coverage = float(abs(pls.windings[0]) % 2) * 0.25;"); fsBuilder->codeAppend("coverage += float(abs(pls.windings[1]) % 2) * 0.25;"); fsBuilder->codeAppend("coverage += float(abs(pls.windings[2]) % 2) * 0.25;"); fsBuilder->codeAppend("coverage += float(abs(pls.windings[3]) % 2) * 0.25;"); fsBuilder->codeAppend("} else {"); fsBuilder->codeAppend("coverage = pls.windings[0] != 0 ? 0.25 : 0.0;"); fsBuilder->codeAppend("coverage += pls.windings[1] != 0 ? 0.25 : 0.0;"); fsBuilder->codeAppend("coverage += pls.windings[2] != 0 ? 0.25 : 0.0;"); fsBuilder->codeAppend("coverage += pls.windings[3] != 0 ? 0.25 : 0.0;"); fsBuilder->codeAppend("}"); if (!fe.colorIgnored()) { this->setupUniformColor(fsBuilder, uniformHandler, args.fOutputColor, &fColorUniform); } fsBuilder->codeAppendf("%s = vec4(coverage);", args.fOutputCoverage); fsBuilder->codeAppendf("%s = vec4(1.0, 0.0, 1.0, 1.0);", args.fOutputColor); }
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 onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ const GrDistanceFieldLCDTextGeoProc& dfTexEffect = args.fGP.cast<GrDistanceFieldLCDTextGeoProc>(); GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; // emit attributes varyingHandler->emitAttributes(dfTexEffect); GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; // setup pass through color if (!dfTexEffect.colorIgnored()) { varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor); } // Setup position this->setupPosition(vertBuilder, uniformHandler, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix(), &fViewMatrixUniform); // emit transforms this->emitTransforms(vertBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName, args.fTransformsIn, args.fTransformsOut); // set up varyings bool isUniformScale = SkToBool(dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask); GrGLSLVertToFrag recipScale(kFloat_GrSLType); GrGLSLVertToFrag st(kVec2f_GrSLType); varyingHandler->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision); vertBuilder->codeAppendf("%s = %s;", st.vsOut(), dfTexEffect.inTextureCoords()->fName); // compute numbers to be hardcoded to convert texture coordinates from int to float SkASSERT(dfTexEffect.numTextures() == 1); GrTexture* atlas = dfTexEffect.textureAccess(0).getTexture(); SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height())); SkScalar recipWidth = 1.0f / atlas->width(); SkScalar recipHeight = 1.0f / atlas->height(); GrGLSLVertToFrag uv(kVec2f_GrSLType); varyingHandler->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision); vertBuilder->codeAppendf("%s = vec2(%.*f, %.*f) * %s;", uv.vsOut(), GR_SIGNIFICANT_POW2_DECIMAL_DIG, recipWidth, GR_SIGNIFICANT_POW2_DECIMAL_DIG, recipHeight, dfTexEffect.inTextureCoords()->fName); // add frag shader code SkAssertResult(fragBuilder->enableFeature( GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); // create LCD offset adjusted by inverse of transform // Use highp to work around aliasing issues fragBuilder->codeAppend(GrGLSLShaderVar::PrecisionString(args.fGLSLCaps, kHigh_GrSLPrecision)); fragBuilder->codeAppendf("vec2 uv = %s;\n", uv.fsIn()); fragBuilder->codeAppend(GrGLSLShaderVar::PrecisionString(args.fGLSLCaps, kHigh_GrSLPrecision)); SkScalar lcdDelta = 1.0f / (3.0f * atlas->width()); if (dfTexEffect.getFlags() & kBGR_DistanceFieldEffectFlag) { fragBuilder->codeAppendf("float delta = -%.*f;\n", SK_FLT_DECIMAL_DIG, lcdDelta); } else { fragBuilder->codeAppendf("float delta = %.*f;\n", SK_FLT_DECIMAL_DIG, lcdDelta); } if (isUniformScale) { fragBuilder->codeAppendf("float dy = abs(dFdy(%s.y));", st.fsIn()); fragBuilder->codeAppend("vec2 offset = vec2(dy*delta, 0.0);"); } else { fragBuilder->codeAppendf("vec2 st = %s;\n", st.fsIn()); fragBuilder->codeAppend("vec2 Jdx = dFdx(st);"); fragBuilder->codeAppend("vec2 Jdy = dFdy(st);"); fragBuilder->codeAppend("vec2 offset = delta*Jdx;"); } // green is distance to uv center fragBuilder->codeAppend("\tvec4 texColor = "); fragBuilder->appendTextureLookup(args.fSamplers[0], "uv", kVec2f_GrSLType); fragBuilder->codeAppend(";\n"); fragBuilder->codeAppend("\tvec3 distance;\n"); fragBuilder->codeAppend("\tdistance.y = texColor.r;\n"); // red is distance to left offset fragBuilder->codeAppend("\tvec2 uv_adjusted = uv - offset;\n"); fragBuilder->codeAppend("\ttexColor = "); fragBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType); fragBuilder->codeAppend(";\n"); fragBuilder->codeAppend("\tdistance.x = texColor.r;\n"); // blue is distance to right offset fragBuilder->codeAppend("\tuv_adjusted = uv + offset;\n"); fragBuilder->codeAppend("\ttexColor = "); fragBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType); fragBuilder->codeAppend(";\n"); fragBuilder->codeAppend("\tdistance.z = texColor.r;\n"); fragBuilder->codeAppend("\tdistance = " "vec3(" SK_DistanceFieldMultiplier ")*(distance - vec3(" SK_DistanceFieldThreshold"));"); // adjust width based on gamma const char* distanceAdjustUniName = nullptr; fDistanceAdjustUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, kVec3f_GrSLType, kDefault_GrSLPrecision, "DistanceAdjust", &distanceAdjustUniName); fragBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName); // To be strictly correct, we should compute the anti-aliasing factor separately // for each color component. However, this is only important when using perspective // transformations, and even then using a single factor seems like a reasonable // trade-off between quality and speed. fragBuilder->codeAppend("float afwidth;"); if (isUniformScale) { // For uniform scale, we adjust for the effect of the transformation on the distance // by using the length of the gradient of the texture coordinates. We use st coordinates // to ensure we're mapping 1:1 from texel space to pixel space. // this gives us a smooth step across approximately one fragment fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*dy;"); } else { // For general transforms, to determine the amount of correction we multiply a unit // vector pointing along the SDF gradient direction by the Jacobian of the st coords // (which is the inverse transform for this fragment) and take the length of the result. fragBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance.r), dFdy(distance.r));"); // the length of the gradient may be 0, so we need to check for this // this also compensates for the Adreno, which likes to drop tiles on division by 0 fragBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);"); fragBuilder->codeAppend("if (dg_len2 < 0.0001) {"); fragBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);"); fragBuilder->codeAppend("} else {"); fragBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);"); fragBuilder->codeAppend("}"); fragBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,"); fragBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);"); // this gives us a smooth step across approximately one fragment fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);"); } fragBuilder->codeAppend( "vec4 val = vec4(smoothstep(vec3(-afwidth), vec3(afwidth), distance), 1.0);"); // set alpha to be max of rgb coverage fragBuilder->codeAppend("val.a = max(max(val.r, val.g), val.b);"); fragBuilder->codeAppendf("%s = val;", args.fOutputCoverage); }
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ const GrDistanceFieldA8TextGeoProc& dfTexEffect = args.fGP.cast<GrDistanceFieldA8TextGeoProc>(); GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; SkAssertResult(fragBuilder->enableFeature( GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; // emit attributes varyingHandler->emitAttributes(dfTexEffect); #ifdef SK_GAMMA_APPLY_TO_A8 // adjust based on gamma const char* distanceAdjustUniName = nullptr; // width, height, 1/(3*width) fDistanceAdjustUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, kFloat_GrSLType, kDefault_GrSLPrecision, "DistanceAdjust", &distanceAdjustUniName); #endif // Setup pass through color if (!dfTexEffect.colorIgnored()) { varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor); } // Setup position this->setupPosition(vertBuilder, uniformHandler, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix(), &fViewMatrixUniform); // emit transforms this->emitTransforms(vertBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName, args.fTransformsIn, args.fTransformsOut); // add varyings GrGLSLVertToFrag recipScale(kFloat_GrSLType); GrGLSLVertToFrag st(kVec2f_GrSLType); bool isSimilarity = SkToBool(dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag); varyingHandler->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision); vertBuilder->codeAppendf("%s = %s;", st.vsOut(), dfTexEffect.inTextureCoords()->fName); // compute numbers to be hardcoded to convert texture coordinates from int to float SkASSERT(dfTexEffect.numTextures() == 1); GrTexture* atlas = dfTexEffect.textureAccess(0).getTexture(); SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height())); SkScalar recipWidth = 1.0f / atlas->width(); SkScalar recipHeight = 1.0f / atlas->height(); GrGLSLVertToFrag uv(kVec2f_GrSLType); varyingHandler->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision); vertBuilder->codeAppendf("%s = vec2(%.*f, %.*f) * %s;", uv.vsOut(), GR_SIGNIFICANT_POW2_DECIMAL_DIG, recipWidth, GR_SIGNIFICANT_POW2_DECIMAL_DIG, recipHeight, dfTexEffect.inTextureCoords()->fName); // Use highp to work around aliasing issues fragBuilder->codeAppend(GrGLSLShaderVar::PrecisionString(args.fGLSLCaps, kHigh_GrSLPrecision)); fragBuilder->codeAppendf("vec2 uv = %s;\n", uv.fsIn()); fragBuilder->codeAppend("\tfloat texColor = "); fragBuilder->appendTextureLookup(args.fSamplers[0], "uv", kVec2f_GrSLType); fragBuilder->codeAppend(".r;\n"); fragBuilder->codeAppend("\tfloat distance = " SK_DistanceFieldMultiplier "*(texColor - " SK_DistanceFieldThreshold ");"); #ifdef SK_GAMMA_APPLY_TO_A8 // adjust width based on gamma fragBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName); #endif fragBuilder->codeAppend("float afwidth;"); if (isSimilarity) { // For uniform scale, we adjust for the effect of the transformation on the distance // by using the length of the gradient of the texture coordinates. We use st coordinates // to ensure we're mapping 1:1 from texel space to pixel space. // this gives us a smooth step across approximately one fragment // we use y to work around a Mali400 bug in the x direction fragBuilder->codeAppendf("afwidth = abs(" SK_DistanceFieldAAFactor "*dFdy(%s.y));", st.fsIn()); } else { // For general transforms, to determine the amount of correction we multiply a unit // vector pointing along the SDF gradient direction by the Jacobian of the st coords // (which is the inverse transform for this fragment) and take the length of the result. fragBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance), dFdy(distance));"); // the length of the gradient may be 0, so we need to check for this // this also compensates for the Adreno, which likes to drop tiles on division by 0 fragBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);"); fragBuilder->codeAppend("if (dg_len2 < 0.0001) {"); fragBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);"); fragBuilder->codeAppend("} else {"); fragBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);"); fragBuilder->codeAppend("}"); fragBuilder->codeAppendf("vec2 Jdx = dFdx(%s);", st.fsIn()); fragBuilder->codeAppendf("vec2 Jdy = dFdy(%s);", st.fsIn()); fragBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,"); fragBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);"); // this gives us a smooth step across approximately one fragment fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);"); } fragBuilder->codeAppend("float val = smoothstep(-afwidth, afwidth, distance);"); fragBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage); }
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ const GrDistanceFieldPathGeoProc& dfTexEffect = args.fGP.cast<GrDistanceFieldPathGeoProc>(); GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; SkAssertResult(fragBuilder->enableFeature( GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; // emit attributes varyingHandler->emitAttributes(dfTexEffect); GrGLSLVertToFrag v(kVec2f_GrSLType); varyingHandler->addVarying("TextureCoords", &v, kHigh_GrSLPrecision); // setup pass through color if (!dfTexEffect.colorIgnored()) { varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor); } vertBuilder->codeAppendf("%s = %s;", v.vsOut(), dfTexEffect.inTextureCoords()->fName); // Setup position this->setupPosition(vertBuilder, uniformHandler, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix(), &fViewMatrixUniform); // emit transforms this->emitTransforms(vertBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName, args.fTransformsIn, args.fTransformsOut); const char* textureSizeUniName = nullptr; fTextureSizeUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, kVec2f_GrSLType, kDefault_GrSLPrecision, "TextureSize", &textureSizeUniName); // Use highp to work around aliasing issues fragBuilder->codeAppend(GrGLSLShaderVar::PrecisionString(args.fGLSLCaps, kHigh_GrSLPrecision)); fragBuilder->codeAppendf("vec2 uv = %s;", v.fsIn()); fragBuilder->codeAppend("float texColor = "); fragBuilder->appendTextureLookup(args.fSamplers[0], "uv", kVec2f_GrSLType); fragBuilder->codeAppend(".r;"); fragBuilder->codeAppend("float distance = " SK_DistanceFieldMultiplier "*(texColor - " SK_DistanceFieldThreshold ");"); fragBuilder->codeAppend(GrGLSLShaderVar::PrecisionString(args.fGLSLCaps, kHigh_GrSLPrecision)); fragBuilder->codeAppendf("vec2 st = uv*%s;", textureSizeUniName); fragBuilder->codeAppend("float afwidth;"); if (dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag) { // For uniform scale, we adjust for the effect of the transformation on the distance // by using the length of the gradient of the texture coordinates. We use st coordinates // to ensure we're mapping 1:1 from texel space to pixel space. // this gives us a smooth step across approximately one fragment fragBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*dFdy(st.y));"); } else { // For general transforms, to determine the amount of correction we multiply a unit // vector pointing along the SDF gradient direction by the Jacobian of the st coords // (which is the inverse transform for this fragment) and take the length of the result. fragBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance), dFdy(distance));"); // the length of the gradient may be 0, so we need to check for this // this also compensates for the Adreno, which likes to drop tiles on division by 0 fragBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);"); fragBuilder->codeAppend("if (dg_len2 < 0.0001) {"); fragBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);"); fragBuilder->codeAppend("} else {"); fragBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);"); fragBuilder->codeAppend("}"); fragBuilder->codeAppend("vec2 Jdx = dFdx(st);"); fragBuilder->codeAppend("vec2 Jdy = dFdy(st);"); fragBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,"); fragBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);"); // this gives us a smooth step across approximately one fragment fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);"); } fragBuilder->codeAppend("float val = smoothstep(-afwidth, afwidth, distance);"); fragBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage); }