void emitCode(EmitArgs& args) override { GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; const GrCircleEffect& _outer = args.fFp.cast<GrCircleEffect>(); (void)_outer; auto edgeType = _outer.edgeType; (void)edgeType; auto center = _outer.center; (void)center; auto radius = _outer.radius; (void)radius; prevRadius = -1.0; circleVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kFloat4_GrSLType, "circle"); fragBuilder->codeAppendf( "float2 prevCenter;\nfloat prevRadius = %f;\nhalf d;\n@if (%d == 2 || %d == 3) {\n " " d = half((length((%s.xy - sk_FragCoord.xy) * %s.w) - 1.0) * %s.z);\n} else {\n " " d = half((1.0 - length((%s.xy - sk_FragCoord.xy) * %s.w)) * %s.z);\n}\n@if " "((%d == 1 || %d == 3) || %d == 4) {\n %s = %s * clamp(d, 0.0, 1.0);\n} else " "{\n %s = d > 0.5 ? %s : half4(0.0);\n}\n", prevRadius, (int)_outer.edgeType, (int)_outer.edgeType, args.fUniformHandler->getUniformCStr(circleVar), args.fUniformHandler->getUniformCStr(circleVar), args.fUniformHandler->getUniformCStr(circleVar), args.fUniformHandler->getUniformCStr(circleVar), args.fUniformHandler->getUniformCStr(circleVar), args.fUniformHandler->getUniformCStr(circleVar), (int)_outer.edgeType, (int)_outer.edgeType, (int)_outer.edgeType, args.fOutputColor, args.fInputColor, args.fOutputColor, args.fInputColor); }
void emitCode(EmitArgs& args) override { GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; const GrTiledGradientEffect& _outer = args.fFp.cast<GrTiledGradientEffect>(); (void)_outer; auto mirror = _outer.mirror; (void)mirror; auto makePremul = _outer.makePremul; (void)makePremul; auto colorsAreOpaque = _outer.colorsAreOpaque; (void)colorsAreOpaque; SkString _child1("_child1"); this->emitChild(_outer.gradLayout_index, &_child1, args); fragBuilder->codeAppendf( "half4 t = %s;\nif (!%s && t.y < 0.0) {\n %s = half4(0.0);\n} else {\n @if " "(%s) {\n half t_1 = t.x - 1.0;\n half tiled_t = (t_1 - 2.0 * " "floor(t_1 * 0.5)) - 1.0;\n if (sk_Caps.mustDoOpBetweenFloorAndAbs) {\n " " tiled_t = clamp(tiled_t, -1.0, 1.0);\n }\n t.x = " "abs(tiled_t);\n } else {\n t.x = fract(t.x);\n }", _child1.c_str(), (_outer.childProcessor(_outer.gradLayout_index).preservesOpaqueInput() ? "true" : "false"), args.fOutputColor, (_outer.mirror ? "true" : "false")); SkString _input0("t"); SkString _child0("_child0"); this->emitChild(_outer.colorizer_index, _input0.c_str(), &_child0, args); fragBuilder->codeAppendf("\n %s = %s;\n}\n@if (%s) {\n %s.xyz *= %s.w;\n}\n", args.fOutputColor, _child0.c_str(), (_outer.makePremul ? "true" : "false"), args.fOutputColor, args.fOutputColor); }
void emitCode(EmitArgs& args) override { GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; this->emitChild(0, args); fragBuilder->codeAppendf("%s.rgb *= %s.rgb;", args.fOutputColor, args.fInputColor); fragBuilder->codeAppendf("%s *= %s.a;", args.fOutputColor, args.fInputColor); }
void emitCode(EmitArgs& args) override { GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; const GrCircleBlurFragmentProcessor& _outer = args.fFp.cast<GrCircleBlurFragmentProcessor>(); (void)_outer; auto circleRect = _outer.circleRect(); (void)circleRect; auto textureRadius = _outer.textureRadius(); (void)textureRadius; auto solidRadius = _outer.solidRadius(); (void)solidRadius; fCircleDataVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType, kDefault_GrSLPrecision, "circleData"); fragBuilder->codeAppendf( "half2 vec = half2(half((sk_FragCoord.x - float(%s.x)) * float(%s.w)), " "half((sk_FragCoord.y - float(%s.y)) * float(%s.w)));\nhalf dist = " "float(length(vec)) + (0.5 - float(%s.z)) * float(%s.w);\n%s = %s * texture(%s, " "float2(half2(dist, 0.5))).%s.w;\n", args.fUniformHandler->getUniformCStr(fCircleDataVar), args.fUniformHandler->getUniformCStr(fCircleDataVar), args.fUniformHandler->getUniformCStr(fCircleDataVar), args.fUniformHandler->getUniformCStr(fCircleDataVar), args.fUniformHandler->getUniformCStr(fCircleDataVar), args.fUniformHandler->getUniformCStr(fCircleDataVar), args.fOutputColor, args.fInputColor ? args.fInputColor : "half4(1)", fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str(), fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str()); }
void GrGLConvexPolyEffect::emitCode(EmitArgs& args) { const GrConvexPolyEffect& cpe = args.fFp.cast<GrConvexPolyEffect>(); const char *edgeArrayName; fEdgeUniform = args.fUniformHandler->addUniformArray(kFragment_GrShaderFlag, kVec3f_GrSLType, kDefault_GrSLPrecision, "edges", cpe.getEdgeCount(), &edgeArrayName); GrGLSLFPFragmentBuilder* 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 emitCode(EmitArgs& args) override { const SwizzleFragmentProcessor& sfp = args.fFp.cast<SwizzleFragmentProcessor>(); const GrSwizzle& swizzle = sfp.swizzle(); GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; fragBuilder->codeAppendf("%s = %s.%s;", args.fOutputColor, args.fInputColor, swizzle.c_str()); }
void emitCode(EmitArgs& args) override { GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; fragBuilder->codeAppendf("%s = ", args.fOutputColor); fragBuilder->appendTextureLookupAndModulate(args.fInputColor, args.fSamplers[0], args.fCoords[0].c_str(), args.fCoords[0].getType()); fragBuilder->codeAppend(";"); }
void GrGLSLFragmentProcessor::emitChild(int childIndex, const char* inputColor, SkString* outputColor, EmitArgs& args) { SkASSERT(outputColor); GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; outputColor->append(fragBuilder->getMangleString()); fragBuilder->codeAppendf("vec4 %s;", outputColor->c_str()); this->internalEmitChild(childIndex, inputColor, outputColor->c_str(), args); }
void GrCircleBlurFragmentProcessor::GLSLProcessor::emitCode(EmitArgs& args) { const char *dataName; // The data is formatted as: // x,y - the center of the circle // z - inner radius that should map to 0th entry in the texture. // w - the inverse of the distance over which the texture is stretched. fDataUniform = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kVec4f_GrSLType, kDefault_GrSLPrecision, "data", &dataName); GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; if (args.fInputColor) { fragBuilder->codeAppendf("vec4 src=%s;", args.fInputColor); } else { fragBuilder->codeAppendf("vec4 src=vec4(1);"); } // We just want to compute "(length(vec) - %s.z + 0.5) * %s.w" but need to rearrange // for precision. fragBuilder->codeAppendf("vec2 vec = vec2( (sk_FragCoord.x - %s.x) * %s.w, " "(sk_FragCoord.y - %s.y) * %s.w );", dataName, dataName, dataName, dataName); fragBuilder->codeAppendf("float dist = length(vec) + (0.5 - %s.z) * %s.w;", dataName, dataName); fragBuilder->codeAppendf("float intensity = "); fragBuilder->appendTextureLookup(args.fTexSamplers[0], "vec2(dist, 0.5)"); fragBuilder->codeAppend(".a;"); fragBuilder->codeAppendf("%s = src * intensity;\n", args.fOutputColor ); }
void onEmitCode(EmitArgs& args) override { GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; // add uniform const char* xformUniName = nullptr; fXformUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kMat22f_GrSLType, kDefault_GrSLPrecision, "Xform", &xformUniName); SkString dstNormalColorName("dstNormalColor"); this->emitChild(0, nullptr, &dstNormalColorName, args); fragBuilder->codeAppendf("vec3 normal = normalize(%s.rgb - vec3(0.5));", dstNormalColorName.c_str()); // If there's no x & y components, return (0, 0, +/- 1) instead to avoid division by 0 fragBuilder->codeAppend( "if (abs(normal.z) > 0.999) {"); fragBuilder->codeAppendf(" %s = normalize(vec4(0.0, 0.0, normal.z, 0.0));", args.fOutputColor); // Else, Normalizing the transformed X and Y, while keeping constant both Z and the // vector's angle in the XY plane. This maintains the "slope" for the surface while // appropriately rotating the normal regardless of any anisotropic scaling that occurs. // Here, we call 'scaling factor' the number that must divide the transformed X and Y so // that the normal's length remains equal to 1. fragBuilder->codeAppend( "} else {"); fragBuilder->codeAppendf(" vec2 transformed = %s * normal.xy;", xformUniName); fragBuilder->codeAppend( " float scalingFactorSquared = " "( (transformed.x * transformed.x) " "+ (transformed.y * transformed.y) )" "/(1.0 - (normal.z * normal.z));"); fragBuilder->codeAppendf(" %s = vec4(transformed*inversesqrt(scalingFactorSquared)," "normal.z, 0.0);", args.fOutputColor); fragBuilder->codeAppend( "}"); }
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { const GrBitmapTextGeoProc& btgp = args.fGP.cast<GrBitmapTextGeoProc>(); GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; // emit attributes varyingHandler->emitAttributes(btgp); const char* atlasSizeInvName; fAtlasSizeInvUniform = uniformHandler->addUniform(kVertex_GrShaderFlag, kFloat2_GrSLType, kHigh_GrSLPrecision, "AtlasSizeInv", &atlasSizeInvName); GrGLSLVarying uv(kFloat2_GrSLType); GrSLType texIdxType = args.fShaderCaps->integerSupport() ? kInt_GrSLType : kFloat_GrSLType; GrGLSLVarying texIdx(texIdxType); append_index_uv_varyings(args, btgp.inTextureCoords().name(), atlasSizeInvName, &uv, &texIdx, nullptr); GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; // Setup pass through color if (btgp.hasVertexColor()) { varyingHandler->addPassThroughAttribute(btgp.inColor(), args.fOutputColor); } else { this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform); } // Setup position gpArgs->fPositionVar = btgp.inPosition().asShaderVar(); // emit transforms this->emitTransforms(vertBuilder, varyingHandler, uniformHandler, btgp.inPosition().asShaderVar(), btgp.localMatrix(), args.fFPCoordTransformHandler); fragBuilder->codeAppend("half4 texColor;"); append_multitexture_lookup(args, btgp.numTextureSamplers(), texIdx, uv.fsIn(), "texColor"); if (btgp.maskFormat() == kARGB_GrMaskFormat) { // modulate by color fragBuilder->codeAppendf("%s = %s * texColor;", args.fOutputColor, args.fOutputColor); fragBuilder->codeAppendf("%s = half4(1);", args.fOutputCoverage); } else { fragBuilder->codeAppendf("%s = texColor;", args.fOutputCoverage); } }
void emitCode(EmitArgs& args) override { GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; const GrSimpleTextureEffect& _outer = args.fFp.cast<GrSimpleTextureEffect>(); (void)_outer; auto matrix = _outer.matrix(); (void)matrix; SkString sk_TransformedCoords2D_0 = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]); fragBuilder->codeAppendf( "%s = %s * texture(%s, %s).%s;\n", args.fOutputColor, args.fInputColor ? args.fInputColor : "half4(1)", fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str(), sk_TransformedCoords2D_0.c_str(), fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str()); }
void emitCode(EmitArgs& args) override { GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; const GrBlurredEdgeFragmentProcessor& _outer = args.fFp.cast<GrBlurredEdgeFragmentProcessor>(); (void)_outer; auto mode = _outer.mode; (void)mode; fragBuilder->codeAppendf( "half factor = 1.0 - %s.w;\n@switch (%d) {\n case 0:\n factor = " "exp((-factor * factor) * 4.0) - 0.017999999999999999;\n break;\n case " "1:\n factor = smoothstep(1.0, 0.0, factor);\n break;\n}\n%s = " "half4(factor);\n", args.fInputColor, (int)_outer.mode, args.fOutputColor); }
void emitCode(EmitArgs& args) override { const GrColorSpaceXformEffect& csxe = args.fFp.cast<GrColorSpaceXformEffect>(); GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; fColorSpaceHelper.emitCode(uniformHandler, csxe.colorXform()); SkString childColor("src_color"); this->emitChild(0, &childColor, args); SkString xformedColor; fragBuilder->appendColorGamutXform(&xformedColor, childColor.c_str(), &fColorSpaceHelper); fragBuilder->codeAppendf("%s = %s * %s;", args.fOutputColor, xformedColor.c_str(), args.fInputColor); }
void emitCode(EmitArgs& args) override { if (nullptr == args.fInputColor) { args.fInputColor = "vec4(1)"; } GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; fragBuilder->codeAppendf("\tfloat luma = dot(vec3(%f, %f, %f), %s.rgb);\n", SK_ITU_BT709_LUM_COEFF_R, SK_ITU_BT709_LUM_COEFF_G, SK_ITU_BT709_LUM_COEFF_B, args.fInputColor); fragBuilder->codeAppendf("\t%s = vec4(0, 0, 0, luma);\n", args.fOutputColor); }
void GLDitherEffect::emitCode(EmitArgs& args) { GrGLSLFPFragmentBuilder* 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 emitCode(EmitArgs& args) override { GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; const GrDitherEffect& _outer = args.fFp.cast<GrDitherEffect>(); (void)_outer; fragBuilder->codeAppendf( "float value;\nfloat range;\n@switch (%d) {\n case 0:\n range = " "0.0039215686274509803;\n break;\n case 1:\n range = " "0.015873015873015872;\n break;\n default:\n range = " "0.0083333333333333332;\n break;\n}\n@if (sk_Caps.integerSupport) {\n " "int x = int(sk_FragCoord.x);\n int y = int(sk_FragCoord.y);\n uint m = " "uint((((((y & 1) << 5 | (x & 1) << 4) | (y & 2) << 2) | (x & 2) << 1) | (y & 4) " ">> 1) | (x & 4) >> 2);\n value = float(m) / 64.0 - 0.4921875;\n} else {\n " "value = fract(sin(dot(sk_FragCoord.xy, vec2(12.989800000000001, " "78.233000000000004))) * 43758.545299999998) - 0.5;\n}\n%s = vec4(clamp(%s.xyz + " "value * range, 0.0, %s.w), %s.w);\n", _outer.rangeType(), args.fOutputColor, args.fInputColor ? args.fInputColor : "vec4(1)", args.fInputColor ? args.fInputColor : "vec4(1)", args.fInputColor ? args.fInputColor : "vec4(1)"); }
void emitCode(EmitArgs& args) override { GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; const GrEllipseEffect& _outer = args.fFp.cast<GrEllipseEffect>(); (void)_outer; auto edgeType = _outer.edgeType(); (void)edgeType; auto center = _outer.center(); (void)center; auto radii = _outer.radii(); (void)radii; prevRadii = float2(-1.0); useScale = !sk_Caps.floatIs32Bits; fEllipseVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kFloat4_GrSLType, kDefault_GrSLPrecision, "ellipse"); if (useScale) { fScaleVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kFloat2_GrSLType, kDefault_GrSLPrecision, "scale"); } fragBuilder->codeAppendf( "float2 prevCenter;\nfloat2 prevRadii = float2(%f, %f);\nbool useScale = " "%s;\nfloat2 d = sk_FragCoord.xy - %s.xy;\n@if (useScale) {\n d *= " "%s.y;\n}\nfloat2 Z = d * %s.zw;\nfloat implicit = dot(Z, d) - 1.0;\nfloat " "grad_dot = 4.0 * dot(Z, Z);\ngrad_dot = max(grad_dot, 0.0001);\nfloat approx_dist " "= implicit * inversesqrt(grad_dot);\n@if (useScale) {\n approx_dist *= " "%s.x;\n}\nhalf alpha;\n@switch (%d) {\n case 0:\n alpha = " "half(approx_dist > 0.0 ? 0.0 : 1.0);\n break;\n case 1:\n ", prevRadii.fX, prevRadii.fY, (useScale ? "true" : "false"), args.fUniformHandler->getUniformCStr(fEllipseVar), fScaleVar.isValid() ? args.fUniformHandler->getUniformCStr(fScaleVar) : "float2(0)", args.fUniformHandler->getUniformCStr(fEllipseVar), fScaleVar.isValid() ? args.fUniformHandler->getUniformCStr(fScaleVar) : "float2(0)", (int)_outer.edgeType()); fragBuilder->codeAppendf( " alpha = half(clamp(0.5 - approx_dist, 0.0, 1.0));\n break;\n case " "2:\n alpha = half(approx_dist > 0.0 ? 1.0 : 0.0);\n break;\n " "case 3:\n alpha = half(clamp(0.5 + approx_dist, 0.0, 1.0));\n " "break;\n default:\n discard;\n}\n%s = %s * alpha;\n", args.fOutputColor, args.fInputColor ? args.fInputColor : "half4(1)"); }
void emitCode(EmitArgs& args) override { GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; const GrAARectEffect& _outer = args.fFp.cast<GrAARectEffect>(); (void)_outer; auto edgeType = _outer.edgeType(); (void)edgeType; auto rect = _outer.rect(); (void)rect; prevRect = float4(-1.0); fRectUniformVar = args.fUniformHandler->addUniform( kFragment_GrShaderFlag, kFloat4_GrSLType, kDefault_GrSLPrecision, "rectUniform"); fragBuilder->codeAppendf( "float4 prevRect = float4(%f, %f, %f, %f);\nhalf alpha;\n@switch (%d) {\n case " "0:\n case 2:\n alpha = half(all(greaterThan(float4(sk_FragCoord.xy, " "%s.zw), float4(%s.xy, sk_FragCoord.xy))) ? 1 : 0);\n break;\n " "default:\n half xSub, ySub;\n xSub = half(min(sk_FragCoord.x - " "%s.x, 0.0));\n xSub += half(min(%s.z - sk_FragCoord.x, 0.0));\n " "ySub = half(min(sk_FragCoord.y - %s.y, 0.0));\n ySub += half(min(%s.w - " "sk_FragCoord.y, 0.0));\n alpha = half((1", prevRect.left(), prevRect.top(), prevRect.right(), prevRect.bottom(), (int)_outer.edgeType(), args.fUniformHandler->getUniformCStr(fRectUniformVar), args.fUniformHandler->getUniformCStr(fRectUniformVar), args.fUniformHandler->getUniformCStr(fRectUniformVar), args.fUniformHandler->getUniformCStr(fRectUniformVar), args.fUniformHandler->getUniformCStr(fRectUniformVar), args.fUniformHandler->getUniformCStr(fRectUniformVar)); fragBuilder->codeAppendf( ".0 + max(float(xSub), -1.0)) * (1.0 + max(float(ySub), -1.0)));\n}\n@if (%d == 2 " "|| %d == 3) {\n alpha = half(1.0 - float(alpha));\n}\n%s = %s * alpha;\n", (int)_outer.edgeType(), (int)_outer.edgeType(), args.fOutputColor, args.fInputColor); }
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 inverse of the profile texture size fDataUniform = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kVec4f_GrSLType, kDefault_GrSLPrecision, "data", &dataName); GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; const char *fragmentPos = fragBuilder->fragmentPosition(); if (args.fInputColor) { fragBuilder->codeAppendf("vec4 src=%s;", args.fInputColor); } else { fragBuilder->codeAppendf("vec4 src=vec4(1);"); } // We just want to compute "length(vec) - %s.z + 0.5) * %s.w" but need to rearrange // for precision fragBuilder->codeAppendf("vec2 vec = vec2( (%s.x - %s.x) * %s.w , (%s.y - %s.y) * %s.w );", fragmentPos, dataName, dataName, fragmentPos, dataName, dataName); fragBuilder->codeAppendf("float dist = length(vec) + ( 0.5 - %s.z ) * %s.w;", dataName, dataName); fragBuilder->codeAppendf("float intensity = "); fragBuilder->appendTextureLookup(args.fTexSamplers[0], "vec2(dist, 0.5)"); fragBuilder->codeAppend(".a;"); fragBuilder->codeAppendf("%s = src * intensity;\n", args.fOutputColor ); }
void emitCode(EmitArgs& args) override { GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; const GrMagnifierEffect& _outer = args.fFp.cast<GrMagnifierEffect>(); (void)_outer; auto bounds = _outer.bounds(); (void)bounds; auto srcRect = _outer.srcRect(); (void)srcRect; auto xInvZoom = _outer.xInvZoom(); (void)xInvZoom; auto yInvZoom = _outer.yInvZoom(); (void)yInvZoom; auto xInvInset = _outer.xInvInset(); (void)xInvInset; auto yInvInset = _outer.yInvInset(); (void)yInvInset; fBoundsUniformVar = args.fUniformHandler->addUniform( kFragment_GrShaderFlag, kFloat4_GrSLType, kDefault_GrSLPrecision, "boundsUniform"); fXInvZoomVar = args.fUniformHandler->addUniform( kFragment_GrShaderFlag, kFloat_GrSLType, kDefault_GrSLPrecision, "xInvZoom"); fYInvZoomVar = args.fUniformHandler->addUniform( kFragment_GrShaderFlag, kFloat_GrSLType, kDefault_GrSLPrecision, "yInvZoom"); fXInvInsetVar = args.fUniformHandler->addUniform( kFragment_GrShaderFlag, kFloat_GrSLType, kDefault_GrSLPrecision, "xInvInset"); fYInvInsetVar = args.fUniformHandler->addUniform( kFragment_GrShaderFlag, kFloat_GrSLType, kDefault_GrSLPrecision, "yInvInset"); fOffsetVar = args.fUniformHandler->addUniform( kFragment_GrShaderFlag, kHalf2_GrSLType, kDefault_GrSLPrecision, "offset"); SkString sk_TransformedCoords2D_0 = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]); fragBuilder->codeAppendf( "float2 coord = %s;\nfloat2 zoom_coord = float2(%s + half2(coord * " "float2(half2(half(%s), half(%s)))));\nfloat2 delta = (coord - %s.xy) * " "%s.zw;\ndelta = min(delta, float2(half2(1.0, 1.0) - half2(delta)));\ndelta *= " "float2(half2(half(%s), half(%s)));\nhalf weight = 0.0;\nif (delta.x < 2.0 && " "delta.y < 2.0) {\n delta = float2(half2(2.0, 2.0) - half2(delta));\n half " "dist = half(length(delta));\n dist = half(max(2.0 - float(dist), 0.0));\n " "weight = half(min(float(dist * dist), 1.0));\n} else {\n ", sk_TransformedCoords2D_0.c_str(), args.fUniformHandler->getUniformCStr(fOffsetVar), args.fUniformHandler->getUniformCStr(fXInvZoomVar), args.fUniformHandler->getUniformCStr(fYInvZoomVar), args.fUniformHandler->getUniformCStr(fBoundsUniformVar), args.fUniformHandler->getUniformCStr(fBoundsUniformVar), args.fUniformHandler->getUniformCStr(fXInvInsetVar), args.fUniformHandler->getUniformCStr(fYInvInsetVar)); fragBuilder->codeAppendf( "float2 delta_squared = delta * delta;\n weight = half(min(min(delta_squared.x, " "delta_squared.y), 1.0));\n}\n%s = texture(%s, mix(coord, zoom_coord, " "float(weight))).%s;\n", args.fOutputColor, fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str(), fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str()); }
void emitCode(EmitArgs& args) override { const TwoPointConicalEffect& effect = args.fFp.cast<TwoPointConicalEffect>(); GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; this->emitUniforms(uniformHandler, effect); fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType, "Conical2FSParams"); SkString p0; // r0 for radial case, r0^2 for strip case p0.appendf("%s", uniformHandler->getUniformVariable(fParamUni).getName().c_str()); const char* tName = "t"; // the gradient GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; SkString coords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]); const char* p = coords2D.c_str(); if (effect.getType() == Type::kRadial) { char sign = effect.diffRadius() < 0 ? '-' : '+'; fragBuilder->codeAppendf("half %s = %clength(%s) - %s;", tName, sign, p, p0.c_str()); } else { // output will default to transparent black (we simply won't write anything // else to it if invalid, instead of discarding or returning prematurely) fragBuilder->codeAppendf("%s = half4(0.0,0.0,0.0,0.0);", args.fOutputColor); fragBuilder->codeAppendf("half temp = %s - %s.y * %s.y;", p0.c_str(), p, p); fragBuilder->codeAppendf("if (temp >= 0) {"); fragBuilder->codeAppendf("half %s = %s.x + sqrt(temp);", tName, p); } this->emitColor(fragBuilder, uniformHandler, args.fShaderCaps, effect, tName, args.fOutputColor, args.fInputColor, args.fTexSamplers); if (effect.getType() != Type::kRadial) { fragBuilder->codeAppendf("}"); } }
void GrGLDisplacementMapEffect::emitCode(EmitArgs& args) { const GrDisplacementMapEffect& displacementMap = args.fFp.cast<GrDisplacementMapEffect>(); const GrTextureDomain& domain = displacementMap.domain(); fScaleUni = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kVec2f_GrSLType, kDefault_GrSLPrecision, "Scale"); const char* scaleUni = args.fUniformHandler->getUniformCStr(fScaleUni); const char* dColor = "dColor"; const char* cCoords = "cCoords"; const char* nearZero = "1e-6"; // Since 6.10352e−5 is the smallest half float, use // a number smaller than that to approximate 0, but // leave room for 32-bit float GPU rounding errors. GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; fragBuilder->codeAppendf("\t\tvec4 %s = ", dColor); fragBuilder->appendTextureLookup(args.fTexSamplers[0], args.fCoords[0].c_str(), args.fCoords[0].getType()); fragBuilder->codeAppend(";\n"); // Unpremultiply the displacement fragBuilder->codeAppendf( "\t\t%s.rgb = (%s.a < %s) ? vec3(0.0) : clamp(%s.rgb / %s.a, 0.0, 1.0);", dColor, dColor, nearZero, dColor, dColor); SkString coords2D = fragBuilder->ensureFSCoords2D(args.fCoords, 1); fragBuilder->codeAppendf("\t\tvec2 %s = %s + %s*(%s.", cCoords, coords2D.c_str(), scaleUni, dColor); switch (displacementMap.xChannelSelector()) { case SkDisplacementMapEffect::kR_ChannelSelectorType: fragBuilder->codeAppend("r"); break; case SkDisplacementMapEffect::kG_ChannelSelectorType: fragBuilder->codeAppend("g"); break; case SkDisplacementMapEffect::kB_ChannelSelectorType: fragBuilder->codeAppend("b"); break; case SkDisplacementMapEffect::kA_ChannelSelectorType: fragBuilder->codeAppend("a"); break; case SkDisplacementMapEffect::kUnknown_ChannelSelectorType: default: SkDEBUGFAIL("Unknown X channel selector"); } switch (displacementMap.yChannelSelector()) { case SkDisplacementMapEffect::kR_ChannelSelectorType: fragBuilder->codeAppend("r"); break; case SkDisplacementMapEffect::kG_ChannelSelectorType: fragBuilder->codeAppend("g"); break; case SkDisplacementMapEffect::kB_ChannelSelectorType: fragBuilder->codeAppend("b"); break; case SkDisplacementMapEffect::kA_ChannelSelectorType: fragBuilder->codeAppend("a"); break; case SkDisplacementMapEffect::kUnknown_ChannelSelectorType: default: SkDEBUGFAIL("Unknown Y channel selector"); } fragBuilder->codeAppend("-vec2(0.5));\t\t"); fGLDomain.sampleTexture(fragBuilder, args.fUniformHandler, args.fGLSLCaps, domain, args.fOutputColor, SkString(cCoords), args.fTexSamplers[1]); fragBuilder->codeAppend(";\n"); }
void GrGLMorphologyEffect::emitCode(EmitArgs& args) { const GrMorphologyEffect& me = args.fFp.cast<GrMorphologyEffect>(); GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; fPixelSizeUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType, kDefault_GrSLPrecision, "PixelSize"); const char* pixelSizeInc = uniformHandler->getUniformCStr(fPixelSizeUni); fRangeUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kVec2f_GrSLType, kDefault_GrSLPrecision, "Range"); const char* range = uniformHandler->getUniformCStr(fRangeUni); GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; SkString coords2D = fragBuilder->ensureFSCoords2D(args.fCoords, 0); const char* func; switch (me.type()) { case GrMorphologyEffect::kErode_MorphologyType: fragBuilder->codeAppendf("\t\t%s = vec4(1, 1, 1, 1);\n", args.fOutputColor); func = "min"; break; case GrMorphologyEffect::kDilate_MorphologyType: fragBuilder->codeAppendf("\t\t%s = vec4(0, 0, 0, 0);\n", args.fOutputColor); func = "max"; break; default: SkFAIL("Unexpected type"); func = ""; // suppress warning break; } const char* dir; switch (me.direction()) { case Gr1DKernelEffect::kX_Direction: dir = "x"; break; case Gr1DKernelEffect::kY_Direction: dir = "y"; break; default: SkFAIL("Unknown filter direction."); dir = ""; // suppress warning } int width = GrMorphologyEffect::WidthFromRadius(me.radius()); // vec2 coord = coord2D; fragBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str()); // coord.x -= radius * pixelSize; fragBuilder->codeAppendf("\t\tcoord.%s -= %d.0 * %s; \n", dir, me.radius(), pixelSizeInc); if (me.useRange()) { // highBound = min(highBound, coord.x + (width-1) * pixelSize); fragBuilder->codeAppendf("\t\tfloat highBound = min(%s.y, coord.%s + %f * %s);", range, dir, float(width - 1), pixelSizeInc); // coord.x = max(lowBound, coord.x); fragBuilder->codeAppendf("\t\tcoord.%s = max(%s.x, coord.%s);", dir, range, dir); } fragBuilder->codeAppendf("\t\tfor (int i = 0; i < %d; i++) {\n", width); fragBuilder->codeAppendf("\t\t\t%s = %s(%s, ", args.fOutputColor, func, args.fOutputColor); fragBuilder->appendTextureLookup(args.fTexSamplers[0], "coord"); fragBuilder->codeAppend(");\n"); // coord.x += pixelSize; fragBuilder->codeAppendf("\t\t\tcoord.%s += %s;\n", dir, pixelSizeInc); if (me.useRange()) { // coord.x = min(highBound, coord.x); fragBuilder->codeAppendf("\t\t\tcoord.%s = min(highBound, coord.%s);", dir, dir); } fragBuilder->codeAppend("\t\t}\n"); SkString modulate; GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor); fragBuilder->codeAppend(modulate.c_str()); }
void GrGLPerlinNoise::emitCode(EmitArgs& args) { const GrPerlinNoiseEffect& pne = args.fFp.cast<GrPerlinNoiseEffect>(); GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; SkString vCoords = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]); fBaseFrequencyUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kVec2f_GrSLType, kDefault_GrSLPrecision, "baseFrequency"); const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni); const char* stitchDataUni = nullptr; if (pne.stitchTiles()) { fStitchDataUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kVec2f_GrSLType, kDefault_GrSLPrecision, "stitchData"); stitchDataUni = uniformHandler->getUniformCStr(fStitchDataUni); } // There are 4 lines, so the center of each line is 1/8, 3/8, 5/8 and 7/8 const char* chanCoordR = "0.125"; const char* chanCoordG = "0.375"; const char* chanCoordB = "0.625"; const char* chanCoordA = "0.875"; const char* chanCoord = "chanCoord"; const char* stitchData = "stitchData"; const char* ratio = "ratio"; const char* noiseVec = "noiseVec"; const char* noiseSmooth = "noiseSmooth"; const char* floorVal = "floorVal"; const char* fractVal = "fractVal"; const char* uv = "uv"; const char* ab = "ab"; const char* latticeIdx = "latticeIdx"; const char* bcoords = "bcoords"; const char* lattice = "lattice"; const char* inc8bit = "0.00390625"; // 1.0 / 256.0 // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a // [-1,1] vector and perform a dot product between that vector and the provided vector. const char* dotLattice = "dot(((%s.ga + %s.rb * vec2(%s)) * vec2(2.0) - vec2(1.0)), %s);"; // Add noise function static const GrGLSLShaderVar gPerlinNoiseArgs[] = { GrGLSLShaderVar(chanCoord, kFloat_GrSLType), GrGLSLShaderVar(noiseVec, kVec2f_GrSLType) }; static const GrGLSLShaderVar gPerlinNoiseStitchArgs[] = { GrGLSLShaderVar(chanCoord, kFloat_GrSLType), GrGLSLShaderVar(noiseVec, kVec2f_GrSLType), GrGLSLShaderVar(stitchData, kVec2f_GrSLType) }; SkString noiseCode; noiseCode.appendf("\tvec4 %s;\n", floorVal); noiseCode.appendf("\t%s.xy = floor(%s);\n", floorVal, noiseVec); noiseCode.appendf("\t%s.zw = %s.xy + vec2(1.0);\n", floorVal, floorVal); noiseCode.appendf("\tvec2 %s = fract(%s);\n", fractVal, noiseVec); // smooth curve : t * t * (3 - 2 * t) noiseCode.appendf("\n\tvec2 %s = %s * %s * (vec2(3.0) - vec2(2.0) * %s);", noiseSmooth, fractVal, fractVal, fractVal); // Adjust frequencies if we're stitching tiles if (pne.stitchTiles()) { noiseCode.appendf("\n\tif(%s.x >= %s.x) { %s.x -= %s.x; }", floorVal, stitchData, floorVal, stitchData); noiseCode.appendf("\n\tif(%s.y >= %s.y) { %s.y -= %s.y; }", floorVal, stitchData, floorVal, stitchData); noiseCode.appendf("\n\tif(%s.z >= %s.x) { %s.z -= %s.x; }", floorVal, stitchData, floorVal, stitchData); noiseCode.appendf("\n\tif(%s.w >= %s.y) { %s.w -= %s.y; }", floorVal, stitchData, floorVal, stitchData); } // Get texture coordinates and normalize noiseCode.appendf("\n\t%s = fract(floor(mod(%s, 256.0)) / vec4(256.0));\n", floorVal, floorVal); // Get permutation for x { SkString xCoords(""); xCoords.appendf("vec2(%s.x, 0.5)", floorVal); noiseCode.appendf("\n\tvec2 %s;\n\t%s.x = ", latticeIdx, latticeIdx); fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str(), kVec2f_GrSLType); noiseCode.append(".r;"); } // Get permutation for x + 1 { SkString xCoords(""); xCoords.appendf("vec2(%s.z, 0.5)", floorVal); noiseCode.appendf("\n\t%s.y = ", latticeIdx); fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str(), kVec2f_GrSLType); noiseCode.append(".r;"); } #if defined(SK_BUILD_FOR_ANDROID) // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3). // The issue is that colors aren't accurate enough on Tegra devices. For example, if an 8 bit // value of 124 (or 0.486275 here) is entered, we can get a texture value of 123.513725 // (or 0.484368 here). The following rounding operation prevents these precision issues from // affecting the result of the noise by making sure that we only have multiples of 1/255. // (Note that 1/255 is about 0.003921569, which is the value used here). noiseCode.appendf("\n\t%s = floor(%s * vec2(255.0) + vec2(0.5)) * vec2(0.003921569);", latticeIdx, latticeIdx); #endif // Get (x,y) coordinates with the permutated x noiseCode.appendf("\n\tvec4 %s = fract(%s.xyxy + %s.yyww);", bcoords, latticeIdx, floorVal); noiseCode.appendf("\n\n\tvec2 %s;", uv); // Compute u, at offset (0,0) { SkString latticeCoords(""); latticeCoords.appendf("vec2(%s.x, %s)", bcoords, chanCoord); noiseCode.appendf("\n\tvec4 %s = ", lattice); fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(), kVec2f_GrSLType); noiseCode.appendf(".bgra;\n\t%s.x = ", uv); noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal); } noiseCode.appendf("\n\t%s.x -= 1.0;", fractVal); // Compute v, at offset (-1,0) { SkString latticeCoords(""); latticeCoords.appendf("vec2(%s.y, %s)", bcoords, chanCoord); noiseCode.append("\n\tlattice = "); fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(), kVec2f_GrSLType); noiseCode.appendf(".bgra;\n\t%s.y = ", uv); noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal); } // Compute 'a' as a linear interpolation of 'u' and 'v' noiseCode.appendf("\n\tvec2 %s;", ab); noiseCode.appendf("\n\t%s.x = mix(%s.x, %s.y, %s.x);", ab, uv, uv, noiseSmooth); noiseCode.appendf("\n\t%s.y -= 1.0;", fractVal); // Compute v, at offset (-1,-1) { SkString latticeCoords(""); latticeCoords.appendf("vec2(%s.w, %s)", bcoords, chanCoord); noiseCode.append("\n\tlattice = "); fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(), kVec2f_GrSLType); noiseCode.appendf(".bgra;\n\t%s.y = ", uv); noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal); } noiseCode.appendf("\n\t%s.x += 1.0;", fractVal); // Compute u, at offset (0,-1) { SkString latticeCoords(""); latticeCoords.appendf("vec2(%s.z, %s)", bcoords, chanCoord); noiseCode.append("\n\tlattice = "); fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str(), kVec2f_GrSLType); noiseCode.appendf(".bgra;\n\t%s.x = ", uv); noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal); } // Compute 'b' as a linear interpolation of 'u' and 'v' noiseCode.appendf("\n\t%s.y = mix(%s.x, %s.y, %s.x);", ab, uv, uv, noiseSmooth); // Compute the noise as a linear interpolation of 'a' and 'b' noiseCode.appendf("\n\treturn mix(%s.x, %s.y, %s.y);\n", ab, ab, noiseSmooth); SkString noiseFuncName; if (pne.stitchTiles()) { fragBuilder->emitFunction(kFloat_GrSLType, "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseStitchArgs), gPerlinNoiseStitchArgs, noiseCode.c_str(), &noiseFuncName); } else { fragBuilder->emitFunction(kFloat_GrSLType, "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseArgs), gPerlinNoiseArgs, noiseCode.c_str(), &noiseFuncName); } // There are rounding errors if the floor operation is not performed here fragBuilder->codeAppendf("\n\t\tvec2 %s = floor(%s.xy) * %s;", noiseVec, vCoords.c_str(), baseFrequencyUni); // Clear the color accumulator fragBuilder->codeAppendf("\n\t\t%s = vec4(0.0);", args.fOutputColor); if (pne.stitchTiles()) { // Set up TurbulenceInitial stitch values. fragBuilder->codeAppendf("vec2 %s = %s;", stitchData, stitchDataUni); } fragBuilder->codeAppendf("float %s = 1.0;", ratio); // Loop over all octaves fragBuilder->codeAppendf("for (int octave = 0; octave < %d; ++octave) {", pne.numOctaves()); fragBuilder->codeAppendf("%s += ", args.fOutputColor); if (pne.type() != SkPerlinNoiseShader::kFractalNoise_Type) { fragBuilder->codeAppend("abs("); } if (pne.stitchTiles()) { fragBuilder->codeAppendf( "vec4(\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s)," "\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s))", noiseFuncName.c_str(), chanCoordR, noiseVec, stitchData, noiseFuncName.c_str(), chanCoordG, noiseVec, stitchData, noiseFuncName.c_str(), chanCoordB, noiseVec, stitchData, noiseFuncName.c_str(), chanCoordA, noiseVec, stitchData); } else { fragBuilder->codeAppendf( "vec4(\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s)," "\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s))", noiseFuncName.c_str(), chanCoordR, noiseVec, noiseFuncName.c_str(), chanCoordG, noiseVec, noiseFuncName.c_str(), chanCoordB, noiseVec, noiseFuncName.c_str(), chanCoordA, noiseVec); } if (pne.type() != SkPerlinNoiseShader::kFractalNoise_Type) { fragBuilder->codeAppendf(")"); // end of "abs(" } fragBuilder->codeAppendf(" * %s;", ratio); fragBuilder->codeAppendf("\n\t\t\t%s *= vec2(2.0);", noiseVec); fragBuilder->codeAppendf("\n\t\t\t%s *= 0.5;", ratio); if (pne.stitchTiles()) { fragBuilder->codeAppendf("\n\t\t\t%s *= vec2(2.0);", stitchData); } fragBuilder->codeAppend("\n\t\t}"); // end of the for loop on octaves if (pne.type() == SkPerlinNoiseShader::kFractalNoise_Type) { // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2 // by fractalNoise and (turbulenceFunctionResult) by turbulence. fragBuilder->codeAppendf("\n\t\t%s = %s * vec4(0.5) + vec4(0.5);", args.fOutputColor,args.fOutputColor); } // Clamp values fragBuilder->codeAppendf("\n\t\t%s = clamp(%s, 0.0, 1.0);", args.fOutputColor, args.fOutputColor); // Pre-multiply the result fragBuilder->codeAppendf("\n\t\t%s = vec4(%s.rgb * %s.aaa, %s.a);\n", args.fOutputColor, args.fOutputColor, args.fOutputColor, args.fOutputColor); }
void GrGLAlphaThresholdFragmentProcessor::emitCode(EmitArgs& args) { GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; fInnerThresholdVar = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType, kDefault_GrSLPrecision, "inner_threshold"); fOuterThresholdVar = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType, kDefault_GrSLPrecision, "outer_threshold"); GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; SkString coords2D = fragBuilder->ensureFSCoords2D(args.fCoords, 0); SkString maskCoords2D = fragBuilder->ensureFSCoords2D(args.fCoords, 1); fragBuilder->codeAppendf("vec2 coord = %s;", coords2D.c_str()); fragBuilder->codeAppendf("vec2 mask_coord = %s;", maskCoords2D.c_str()); fragBuilder->codeAppend("vec4 input_color = "); fragBuilder->appendTextureLookup(args.fTexSamplers[0], "coord"); fragBuilder->codeAppend(";"); fragBuilder->codeAppend("vec4 mask_color = "); fragBuilder->appendTextureLookup(args.fTexSamplers[1], "mask_coord"); fragBuilder->codeAppend(";"); fragBuilder->codeAppendf("float inner_thresh = %s;", uniformHandler->getUniformCStr(fInnerThresholdVar)); fragBuilder->codeAppendf("float outer_thresh = %s;", uniformHandler->getUniformCStr(fOuterThresholdVar)); fragBuilder->codeAppend("float mask = mask_color.a;"); fragBuilder->codeAppend("vec4 color = input_color;"); fragBuilder->codeAppend("if (mask < 0.5) {" "if (color.a > outer_thresh) {" "float scale = outer_thresh / color.a;" "color.rgb *= scale;" "color.a = outer_thresh;" "}" "} else if (color.a < inner_thresh) {" "float scale = inner_thresh / max(0.001, color.a);" "color.rgb *= scale;" "color.a = inner_thresh;" "}"); fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr4("color")).c_str()); }
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { const DefaultGeoProc& gp = args.fGP.cast<DefaultGeoProc>(); GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; // emit attributes varyingHandler->emitAttributes(gp); // Setup pass through color if (gp.hasVertexColor()) { GrGLSLVarying varying(kHalf4_GrSLType); varyingHandler->addVarying("color", &varying); // There are several optional steps to process the color. Start with the attribute: vertBuilder->codeAppendf("half4 color = %s;", gp.inColor()->fName); // Linearize if (gp.linearizeColor()) { SkString srgbFuncName; static const GrShaderVar gSrgbArgs[] = { GrShaderVar("x", kHalf_GrSLType), }; vertBuilder->emitFunction(kHalf_GrSLType, "srgb_to_linear", SK_ARRAY_COUNT(gSrgbArgs), gSrgbArgs, "return (x <= 0.04045) ? (x / 12.92) " ": pow((x + 0.055) / 1.055, 2.4);", &srgbFuncName); vertBuilder->codeAppendf("color = half4(%s(%s.r), %s(%s.g), %s(%s.b), %s.a);", srgbFuncName.c_str(), gp.inColor()->fName, srgbFuncName.c_str(), gp.inColor()->fName, srgbFuncName.c_str(), gp.inColor()->fName, gp.inColor()->fName); } // For SkColor, do a red/blue swap and premul if (gp.fFlags & kColorAttributeIsSkColor_GPFlag) { vertBuilder->codeAppend("color = half4(color.a * color.bgr, color.a);"); } // Do color-correction to destination gamut if (gp.linearizeColor()) { fColorSpaceHelper.emitCode(uniformHandler, gp.fColorSpaceXform.get(), kVertex_GrShaderFlag); if (fColorSpaceHelper.isValid()) { SkString xformedColor; vertBuilder->appendColorGamutXform(&xformedColor, "color", &fColorSpaceHelper); vertBuilder->codeAppendf("color = %s;", xformedColor.c_str()); } } vertBuilder->codeAppendf("%s = color;\n", varying.vsOut()); fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, varying.fsIn()); } else { this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform); } // Setup position this->writeOutputPosition(vertBuilder, uniformHandler, gpArgs, gp.inPosition()->fName, gp.viewMatrix(), &fViewMatrixUniform); if (gp.hasExplicitLocalCoords()) { // emit transforms with explicit local coords this->emitTransforms(vertBuilder, varyingHandler, uniformHandler, gp.inLocalCoords()->asShaderVar(), gp.localMatrix(), args.fFPCoordTransformHandler); } else { // emit transforms with position this->emitTransforms(vertBuilder, varyingHandler, uniformHandler, gp.inPosition()->asShaderVar(), gp.localMatrix(), args.fFPCoordTransformHandler); } // Setup coverage as pass through if (gp.hasVertexCoverage()) { fragBuilder->codeAppendf("half alpha = 1.0;"); varyingHandler->addPassThroughAttribute(gp.inCoverage(), "alpha"); fragBuilder->codeAppendf("%s = half4(alpha);", args.fOutputCoverage); } else if (gp.coverage() == 0xff) { fragBuilder->codeAppendf("%s = half4(1);", args.fOutputCoverage); } else { const char* fragCoverage; fCoverageUniform = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType, "Coverage", &fragCoverage); fragBuilder->codeAppendf("%s = half4(%s);", args.fOutputCoverage, fragCoverage); } }
void emitCode(EmitArgs& args) override { const TwoPointConicalEffect& effect = args.fFp.cast<TwoPointConicalEffect>(); GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; this->emitUniforms(uniformHandler, effect); fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType, "Conical2FSParams"); SkString p0; // 1 / r1 SkString p1; // f = focalX = r0 / (r0 - r1) p0.appendf("%s.x", uniformHandler->getUniformVariable(fParamUni).getName().c_str()); p1.appendf("%s.y", uniformHandler->getUniformVariable(fParamUni).getName().c_str()); const char* tName = "t"; // the gradient GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; SkString coords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]); const char* p = coords2D.c_str(); if (effect.isFocalOnCircle()) { fragBuilder->codeAppendf("half x_t = dot(%s, %s) / %s.x;", p, p, p); } else if (effect.isWellBehaved()) { fragBuilder->codeAppendf("half x_t = length(%s) - %s.x * %s;", p, p, p0.c_str()); } else { char sign = (effect.isSwapped() || !effect.isRadiusIncreasing()) ? '-' : ' '; fragBuilder->codeAppendf("half temp = %s.x * %s.x - %s.y * %s.y;", p, p, p, p); // Initialize x_t to illegal state fragBuilder->codeAppendf("half x_t = -1;"); // Only do sqrt if temp >= 0; this is significantly slower than checking temp >= 0 in // the if statement that checks r(t) >= 0. But GPU may break if we sqrt a negative // float. (Although I havevn't observed that on any devices so far, and the old approach // also does sqrt negative value without a check.) If the performance is really // critical, maybe we should just compute the area where temp and x_t are always // valid and drop all these ifs. fragBuilder->codeAppendf("if (temp >= 0) {"); fragBuilder->codeAppendf("x_t = (%csqrt(temp) - %s.x * %s);", sign, p, p0.c_str()); fragBuilder->codeAppendf("}"); } // empty sign is positive char sign = effect.isRadiusIncreasing() ? ' ' : '-'; // "+ 0" is much faster than "+ p1" so we specialize the natively focal case where p1 = 0. fragBuilder->codeAppendf("half %s = %cx_t + %s;", tName, sign, effect.isNativelyFocal() ? "0" : p1.c_str()); if (!effect.isWellBehaved()) { // output will default to transparent black (we simply won't write anything // else to it if invalid, instead of discarding or returning prematurely) fragBuilder->codeAppendf("%s = half4(0.0,0.0,0.0,0.0);", args.fOutputColor); fragBuilder->codeAppendf("if (x_t > 0.0) {"); } if (effect.isSwapped()) { fragBuilder->codeAppendf("%s = 1 - %s;", tName, tName); } this->emitColor(fragBuilder, uniformHandler, args.fShaderCaps, effect, tName, args.fOutputColor, args.fInputColor, args.fTexSamplers); if (!effect.isWellBehaved()) { fragBuilder->codeAppend("};"); } }
void GrGLSLFragmentProcessor::internalEmitChild(int childIndex, const char* inputColor, const char* outputColor, EmitArgs& args) { GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; fragBuilder->onBeforeChildProcEmitCode(); // call first so mangleString is updated const GrFragmentProcessor& childProc = args.fFp.childProcessor(childIndex); /* * We now want to find the subset of coords and samplers that belong to the child and its * descendants and put that into childCoords and childSamplers. To do so, we'll do a forwards * linear search. * * Explanation: * Each GrFragmentProcessor has a copy of all the transforms and textures of itself and * all procs in its subtree. For example, suppose we have frag proc A, who has two children B * and D. B has a child C, and D has two children E and F. Each frag proc's transforms array * contains its own transforms, followed by the transforms of all its descendants (i.e. preorder * traversal). Suppose procs A, B, C, D, E, F have 1, 2, 1, 1, 3, 2 transforms respectively. * * (A) * [a1,b1,b2,c1,d1,e1,e2,e3,f1,f2] * / \ * / \ * (B) (D) * [b1,b2,c1] [d1,e1,e2,e3,f1,f2] * / / \ * / / \ * (C) (E) (F) * [c1] [e1,e2,e3] [f1,f2] * * So if we're inside proc A's emitCode, and A is about to call emitCode on proc D, we want the * EmitArgs that's passed onto D to only contain its and its descendants' coords. The * EmitArgs given to A would contain the transforms [a1,b1,b2,c1,d1,e1,e2,e3,f1,f2], and we want * to extract the subset [d1,e1,e2,e3,f1,f2] to pass on to D. We can do this with a linear * search since we know that A has 1 transform (using A.numTransformsExclChildren()), and B's * subtree has 3 transforms (using B.numTransforms()), so we know the start of D's transforms is * 4 after the start of A's transforms. * Textures work the same way as transforms. */ int firstCoordAt = args.fFp.numTransformsExclChildren(); int firstSamplerAt = args.fFp.numTexturesExclChildren(); for (int i = 0; i < childIndex; ++i) { firstCoordAt += args.fFp.childProcessor(i).numTransforms(); firstSamplerAt += args.fFp.childProcessor(i).numTextures(); } GrGLSLTransformedCoordsArray childCoords; TextureSamplerArray childSamplers; if (childProc.numTransforms() > 0) { childCoords.push_back_n(childProc.numTransforms(), &args.fCoords[firstCoordAt]); } if (childProc.numTextures() > 0) { childSamplers.push_back_n(childProc.numTextures(), &args.fSamplers[firstSamplerAt]); } // emit the code for the child in its own scope fragBuilder->codeAppend("{\n"); fragBuilder->codeAppendf("// Child Index %d (mangle: %s): %s\n", childIndex, fragBuilder->getMangleString().c_str(), childProc.name()); EmitArgs childArgs(fragBuilder, args.fUniformHandler, args.fGLSLCaps, childProc, outputColor, inputColor, childCoords, childSamplers); this->childProcessor(childIndex)->emitCode(childArgs); fragBuilder->codeAppend("}\n"); fragBuilder->onAfterChildProcEmitCode(); }
void GrColorCubeEffect::GLSLProcessor::emitCode(EmitArgs& args) { if (nullptr == args.fInputColor) { args.fInputColor = "vec4(1)"; } GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; fColorCubeSizeUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType, kDefault_GrSLPrecision, "Size"); const char* colorCubeSizeUni = uniformHandler->getUniformCStr(fColorCubeSizeUni); fColorCubeInvSizeUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType, kDefault_GrSLPrecision, "InvSize"); const char* colorCubeInvSizeUni = uniformHandler->getUniformCStr(fColorCubeInvSizeUni); const char* nonZeroAlpha = "nonZeroAlpha"; const char* unPMColor = "unPMColor"; const char* cubeIdx = "cubeIdx"; const char* cCoords1 = "cCoords1"; const char* cCoords2 = "cCoords2"; // Note: if implemented using texture3D in OpenGL ES older than OpenGL ES 3.0, // the shader might need "#extension GL_OES_texture_3D : enable". GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; // Unpremultiply color fragBuilder->codeAppendf("\tfloat %s = max(%s.a, 0.00001);\n", nonZeroAlpha, args.fInputColor); fragBuilder->codeAppendf("\tvec4 %s = vec4(%s.rgb / %s, %s);\n", unPMColor, args.fInputColor, nonZeroAlpha, nonZeroAlpha); // Fit input color into the cube. fragBuilder->codeAppendf( "vec3 %s = vec3(%s.rg * vec2((%s - 1.0) * %s) + vec2(0.5 * %s), %s.b * (%s - 1.0));\n", cubeIdx, unPMColor, colorCubeSizeUni, colorCubeInvSizeUni, colorCubeInvSizeUni, unPMColor, colorCubeSizeUni); // Compute y coord for for texture fetches. fragBuilder->codeAppendf("vec2 %s = vec2(%s.r, (floor(%s.b) + %s.g) * %s);\n", cCoords1, cubeIdx, cubeIdx, cubeIdx, colorCubeInvSizeUni); fragBuilder->codeAppendf("vec2 %s = vec2(%s.r, (ceil(%s.b) + %s.g) * %s);\n", cCoords2, cubeIdx, cubeIdx, cubeIdx, colorCubeInvSizeUni); // Apply the cube. fragBuilder->codeAppendf("%s = vec4(mix(", args.fOutputColor); fragBuilder->appendTextureLookup(args.fSamplers[0], cCoords1); fragBuilder->codeAppend(".bgr, "); fragBuilder->appendTextureLookup(args.fSamplers[0], cCoords2); // Premultiply color by alpha. Note that the input alpha is not modified by this shader. fragBuilder->codeAppendf(".bgr, fract(%s.b)) * vec3(%s), %s.a);\n", cubeIdx, nonZeroAlpha, args.fInputColor); }