void onEmitCode(const EmitArgs& args) override { const CoverageSetOpXP& xp = args.fXP.cast<CoverageSetOpXP>(); GrGLFPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); if (xp.invertCoverage()) { fsBuilder->codeAppendf("%s = 1.0 - %s;", args.fOutputPrimary, args.fInputCoverage); } else { fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputCoverage); } }
void GrGLMagnifierEffect::emitCode(GrGLFPBuilder* builder, const GrFragmentProcessor&, const char* outputColor, const char* inputColor, const TransformedCoordsArray& coords, const TextureSamplerArray& samplers) { fOffsetVar = builder->addUniform( GrGLProgramBuilder::kFragment_Visibility | GrGLProgramBuilder::kVertex_Visibility, kVec2f_GrSLType, kDefault_GrSLPrecision, "Offset"); fInvZoomVar = builder->addUniform( GrGLProgramBuilder::kFragment_Visibility | GrGLProgramBuilder::kVertex_Visibility, kVec2f_GrSLType, kDefault_GrSLPrecision, "InvZoom"); fInvInsetVar = builder->addUniform( GrGLProgramBuilder::kFragment_Visibility | GrGLProgramBuilder::kVertex_Visibility, kVec2f_GrSLType, kDefault_GrSLPrecision, "InvInset"); GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0); fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str()); fsBuilder->codeAppendf("\t\tvec2 zoom_coord = %s + %s * %s;\n", builder->getUniformCStr(fOffsetVar), coords2D.c_str(), builder->getUniformCStr(fInvZoomVar)); fsBuilder->codeAppend("\t\tvec2 delta = min(coord, vec2(1.0, 1.0) - coord);\n"); fsBuilder->codeAppendf("\t\tdelta = delta * %s;\n", builder->getUniformCStr(fInvInsetVar)); fsBuilder->codeAppend("\t\tfloat weight = 0.0;\n"); fsBuilder->codeAppend("\t\tif (delta.s < 2.0 && delta.t < 2.0) {\n"); fsBuilder->codeAppend("\t\t\tdelta = vec2(2.0, 2.0) - delta;\n"); fsBuilder->codeAppend("\t\t\tfloat dist = length(delta);\n"); fsBuilder->codeAppend("\t\t\tdist = max(2.0 - dist, 0.0);\n"); fsBuilder->codeAppend("\t\t\tweight = min(dist * dist, 1.0);\n"); fsBuilder->codeAppend("\t\t} else {\n"); fsBuilder->codeAppend("\t\t\tvec2 delta_squared = delta * delta;\n"); fsBuilder->codeAppend("\t\t\tweight = min(min(delta_squared.x, delta_squared.y), 1.0);\n"); fsBuilder->codeAppend("\t\t}\n"); fsBuilder->codeAppend("\t\tvec2 mix_coord = mix(coord, zoom_coord, weight);\n"); fsBuilder->codeAppend("\t\tvec4 output_color = "); fsBuilder->appendTextureLookup(samplers[0], "mix_coord"); fsBuilder->codeAppend(";\n"); fsBuilder->codeAppendf("\t\t%s = output_color;", outputColor); SkString modulate; GrGLSLMulVarBy4f(&modulate, outputColor, inputColor); fsBuilder->codeAppend(modulate.c_str()); }
void GrColorCubeEffect::GLProcessor::emitCode(GrGLFPBuilder* builder, const GrFragmentProcessor&, const char* outputColor, const char* inputColor, const TransformedCoordsArray& coords, const TextureSamplerArray& samplers) { if (NULL == inputColor) { inputColor = "vec4(1)"; } fColorCubeSizeUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kFloat_GrSLType, kDefault_GrSLPrecision, "Size"); const char* colorCubeSizeUni = builder->getUniformCStr(fColorCubeSizeUni); fColorCubeInvSizeUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kFloat_GrSLType, kDefault_GrSLPrecision, "InvSize"); const char* colorCubeInvSizeUni = builder->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". GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); // Unpremultiply color fsBuilder->codeAppendf("\tfloat %s = max(%s.a, 0.00001);\n", nonZeroAlpha, inputColor); fsBuilder->codeAppendf("\tvec4 %s = vec4(%s.rgb / %s, %s);\n", unPMColor, inputColor, nonZeroAlpha, nonZeroAlpha); // Fit input color into the cube. fsBuilder->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. fsBuilder->codeAppendf("vec2 %s = vec2(%s.r, (floor(%s.b) + %s.g) * %s);\n", cCoords1, cubeIdx, cubeIdx, cubeIdx, colorCubeInvSizeUni); fsBuilder->codeAppendf("vec2 %s = vec2(%s.r, (ceil(%s.b) + %s.g) * %s);\n", cCoords2, cubeIdx, cubeIdx, cubeIdx, colorCubeInvSizeUni); // Apply the cube. fsBuilder->codeAppendf("%s = vec4(mix(", outputColor); fsBuilder->appendTextureLookup(samplers[0], cCoords1); fsBuilder->codeAppend(".rgb, "); fsBuilder->appendTextureLookup(samplers[0], cCoords2); // Premultiply color by alpha. Note that the input alpha is not modified by this shader. fsBuilder->codeAppendf(".rgb, fract(%s.b)) * vec3(%s), %s.a);\n", cubeIdx, nonZeroAlpha, inputColor); }
void GrGLConvexPolyEffect::emitCode(GrGLFPBuilder* builder, const GrFragmentProcessor& fp, const char* outputColor, const char* inputColor, const TransformedCoordsArray&, const TextureSamplerArray& samplers) { const GrConvexPolyEffect& cpe = fp.cast<GrConvexPolyEffect>(); const char *edgeArrayName; fEdgeUniform = builder->addUniformArray(GrGLProgramBuilder::kFragment_Visibility, kVec3f_GrSLType, kDefault_GrSLPrecision, "edges", cpe.getEdgeCount(), &edgeArrayName); GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); fsBuilder->codeAppend("\t\tfloat alpha = 1.0;\n"); fsBuilder->codeAppend("\t\tfloat edge;\n"); const char* fragmentPos = fsBuilder->fragmentPosition(); for (int i = 0; i < cpe.getEdgeCount(); ++i) { fsBuilder->codeAppendf("\t\tedge = dot(%s[%d], vec3(%s.x, %s.y, 1));\n", edgeArrayName, i, fragmentPos, fragmentPos); if (GrProcessorEdgeTypeIsAA(cpe.getEdgeType())) { fsBuilder->codeAppend("\t\tedge = clamp(edge, 0.0, 1.0);\n"); } else { fsBuilder->codeAppend("\t\tedge = edge >= 0.5 ? 1.0 : 0.0;\n"); } fsBuilder->codeAppend("\t\talpha *= edge;\n"); } // Woe is me. See skbug.com/2149. if (kTegra2_GrGLRenderer == builder->ctxInfo().renderer()) { fsBuilder->codeAppend("\t\tif (-1.0 == alpha) {\n\t\t\tdiscard;\n\t\t}\n"); } if (GrProcessorEdgeTypeIsInverseFill(cpe.getEdgeType())) { fsBuilder->codeAppend("\talpha = 1.0 - alpha;\n"); } fsBuilder->codeAppendf("\t%s = %s;\n", outputColor, (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str()); }
void GLAARectEffect::emitCode(GrGLFPBuilder* builder, const GrFragmentProcessor& fp, const char* outputColor, const char* inputColor, const TransformedCoordsArray&, const TextureSamplerArray& samplers) { const AARectEffect& aare = fp.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 = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kVec4f_GrSLType, kDefault_GrSLPrecision, "rect", &rectName); GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); const char* fragmentPos = fsBuilder->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. fsBuilder->codeAppend("\t\tfloat xSub, ySub;\n"); fsBuilder->codeAppendf("\t\txSub = min(%s.x - %s.x, 0.0);\n", fragmentPos, rectName); fsBuilder->codeAppendf("\t\txSub += min(%s.z - %s.x, 0.0);\n", rectName, fragmentPos); fsBuilder->codeAppendf("\t\tySub = min(%s.y - %s.y, 0.0);\n", fragmentPos, rectName); fsBuilder->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. fsBuilder->codeAppendf("\t\tfloat alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));\n"); } else { fsBuilder->codeAppendf("\t\tfloat alpha = 1.0;\n"); fsBuilder->codeAppendf("\t\talpha *= (%s.x - %s.x) > -0.5 ? 1.0 : 0.0;\n", fragmentPos, rectName); fsBuilder->codeAppendf("\t\talpha *= (%s.z - %s.x) > -0.5 ? 1.0 : 0.0;\n", rectName, fragmentPos); fsBuilder->codeAppendf("\t\talpha *= (%s.y - %s.y) > -0.5 ? 1.0 : 0.0;\n", fragmentPos, rectName); fsBuilder->codeAppendf("\t\talpha *= (%s.w - %s.y) > -0.5 ? 1.0 : 0.0;\n", rectName, fragmentPos); } if (GrProcessorEdgeTypeIsInverseFill(aare.getEdgeType())) { fsBuilder->codeAppend("\t\talpha = 1.0 - alpha;\n"); } fsBuilder->codeAppendf("\t\t%s = %s;\n", outputColor, (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str()); }
void onEmitCode(const EmitArgs& args) override { GrGLFPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); const char* dstColor = fsBuilder->dstColor(); fKUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility, kVec4f_GrSLType, kDefault_GrSLPrecision, "k"); const char* kUni = args.fPB->getUniformCStr(fKUni); add_arithmetic_code(fsBuilder, args.fInputColor, dstColor, args.fOutputPrimary, kUni, fEnforcePMColor); fsBuilder->codeAppendf("%s = %s * %s + (vec4(1.0) - %s) * %s;", args.fOutputPrimary, args.fOutputPrimary, args.fInputCoverage, args.fInputCoverage, dstColor); }
void emitCode(GrGLFPBuilder* builder, const GrFragmentProcessor& fp, const char* outputColor, const char* inputColor, const TransformedCoordsArray& coords, const TextureSamplerArray& samplers) override { GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); fsBuilder->codeAppend("vec4 bgColor = "); fsBuilder->appendTextureLookup(samplers[0], coords[0].c_str(), coords[0].getType()); fsBuilder->codeAppendf(";"); const char* dstColor = "bgColor"; fKUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kVec4f_GrSLType, kDefault_GrSLPrecision, "k"); const char* kUni = builder->getUniformCStr(fKUni); add_arithmetic_code(fsBuilder, inputColor, dstColor, outputColor, kUni, fEnforcePMColor); }
void GrGLDisplacementMapEffect::emitCode(GrGLFPBuilder* builder, const GrFragmentProcessor& fp, const char* outputColor, const char* inputColor, const TransformedCoordsArray& coords, const TextureSamplerArray& samplers) { const GrTextureDomain& domain = fp.cast<GrDisplacementMapEffect>().domain(); sk_ignore_unused_variable(inputColor); fScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kVec2f_GrSLType, kDefault_GrSLPrecision, "Scale"); const char* scaleUni = builder->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. GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); fsBuilder->codeAppendf("\t\tvec4 %s = ", dColor); fsBuilder->appendTextureLookup(samplers[0], coords[0].c_str(), coords[0].getType()); fsBuilder->codeAppend(";\n"); // Unpremultiply the displacement fsBuilder->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 = fsBuilder->ensureFSCoords2D(coords, 1); fsBuilder->codeAppendf("\t\tvec2 %s = %s + %s*(%s.", cCoords, coords2D.c_str(), scaleUni, dColor); switch (fXChannelSelector) { case SkDisplacementMapEffect::kR_ChannelSelectorType: fsBuilder->codeAppend("r"); break; case SkDisplacementMapEffect::kG_ChannelSelectorType: fsBuilder->codeAppend("g"); break; case SkDisplacementMapEffect::kB_ChannelSelectorType: fsBuilder->codeAppend("b"); break; case SkDisplacementMapEffect::kA_ChannelSelectorType: fsBuilder->codeAppend("a"); break; case SkDisplacementMapEffect::kUnknown_ChannelSelectorType: default: SkDEBUGFAIL("Unknown X channel selector"); } switch (fYChannelSelector) { case SkDisplacementMapEffect::kR_ChannelSelectorType: fsBuilder->codeAppend("r"); break; case SkDisplacementMapEffect::kG_ChannelSelectorType: fsBuilder->codeAppend("g"); break; case SkDisplacementMapEffect::kB_ChannelSelectorType: fsBuilder->codeAppend("b"); break; case SkDisplacementMapEffect::kA_ChannelSelectorType: fsBuilder->codeAppend("a"); break; case SkDisplacementMapEffect::kUnknown_ChannelSelectorType: default: SkDEBUGFAIL("Unknown Y channel selector"); } fsBuilder->codeAppend("-vec2(0.5));\t\t"); fGLDomain.sampleTexture(fsBuilder, domain, outputColor, SkString(cCoords), samplers[1]); fsBuilder->codeAppend(";\n"); }
void GrGLMorphologyEffect::emitCode(GrGLFPBuilder* builder, const GrFragmentProcessor&, const char* outputColor, const char* inputColor, const TransformedCoordsArray& coords, const TextureSamplerArray& samplers) { fPixelSizeUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kFloat_GrSLType, kDefault_GrSLPrecision, "PixelSize"); const char* pixelSizeInc = builder->getUniformCStr(fPixelSizeUni); fRangeUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kVec2f_GrSLType, kDefault_GrSLPrecision, "Range"); const char* range = builder->getUniformCStr(fRangeUni); GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0); const char* func; switch (fType) { case GrMorphologyEffect::kErode_MorphologyType: fsBuilder->codeAppendf("\t\t%s = vec4(1, 1, 1, 1);\n", outputColor); func = "min"; break; case GrMorphologyEffect::kDilate_MorphologyType: fsBuilder->codeAppendf("\t\t%s = vec4(0, 0, 0, 0);\n", outputColor); func = "max"; break; default: SkFAIL("Unexpected type"); func = ""; // suppress warning break; } const char* dir; switch (fDirection) { case Gr1DKernelEffect::kX_Direction: dir = "x"; break; case Gr1DKernelEffect::kY_Direction: dir = "y"; break; default: SkFAIL("Unknown filter direction."); dir = ""; // suppress warning } // vec2 coord = coord2D; fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str()); // coord.x -= radius * pixelSize; fsBuilder->codeAppendf("\t\tcoord.%s -= %d.0 * %s; \n", dir, fRadius, pixelSizeInc); if (fUseRange) { // highBound = min(highBound, coord.x + (width-1) * pixelSize); fsBuilder->codeAppendf("\t\tfloat highBound = min(%s.y, coord.%s + %f * %s);", range, dir, float(width() - 1), pixelSizeInc); // coord.x = max(lowBound, coord.x); fsBuilder->codeAppendf("\t\tcoord.%s = max(%s.x, coord.%s);", dir, range, dir); } fsBuilder->codeAppendf("\t\tfor (int i = 0; i < %d; i++) {\n", width()); fsBuilder->codeAppendf("\t\t\t%s = %s(%s, ", outputColor, func, outputColor); fsBuilder->appendTextureLookup(samplers[0], "coord"); fsBuilder->codeAppend(");\n"); // coord.x += pixelSize; fsBuilder->codeAppendf("\t\t\tcoord.%s += %s;\n", dir, pixelSizeInc); if (fUseRange) { // coord.x = min(highBound, coord.x); fsBuilder->codeAppendf("\t\t\tcoord.%s = min(highBound, coord.%s);", dir, dir); } fsBuilder->codeAppend("\t\t}\n"); SkString modulate; GrGLSLMulVarBy4f(&modulate, outputColor, inputColor); fsBuilder->codeAppend(modulate.c_str()); }
void GrGLBicubicEffect::emitCode(GrGLFPBuilder* builder, const GrFragmentProcessor& effect, const char* outputColor, const char* inputColor, const TransformedCoordsArray& coords, const TextureSamplerArray& samplers) { const GrTextureDomain& domain = effect.cast<GrBicubicEffect>().domain(); fCoefficientsUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kMat44f_GrSLType, kDefault_GrSLPrecision, "Coefficients"); fImageIncrementUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kVec2f_GrSLType, kDefault_GrSLPrecision, "ImageIncrement"); const char* imgInc = builder->getUniformCStr(fImageIncrementUni); const char* coeff = builder->getUniformCStr(fCoefficientsUni); SkString cubicBlendName; static const GrGLShaderVar gCubicBlendArgs[] = { GrGLShaderVar("coefficients", kMat44f_GrSLType), GrGLShaderVar("t", kFloat_GrSLType), GrGLShaderVar("c0", kVec4f_GrSLType), GrGLShaderVar("c1", kVec4f_GrSLType), GrGLShaderVar("c2", kVec4f_GrSLType), GrGLShaderVar("c3", kVec4f_GrSLType), }; GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0); fsBuilder->emitFunction(kVec4f_GrSLType, "cubicBlend", SK_ARRAY_COUNT(gCubicBlendArgs), gCubicBlendArgs, "\tvec4 ts = vec4(1.0, t, t * t, t * t * t);\n" "\tvec4 c = coefficients * ts;\n" "\treturn c.x * c0 + c.y * c1 + c.z * c2 + c.w * c3;\n", &cubicBlendName); fsBuilder->codeAppendf("\tvec2 coord = %s - %s * vec2(0.5);\n", coords2D.c_str(), imgInc); // We unnormalize the coord in order to determine our fractional offset (f) within the texel // We then snap coord to a texel center and renormalize. The snap prevents cases where the // starting coords are near a texel boundary and accumulations of imgInc would cause us to skip/ // double hit a texel. fsBuilder->codeAppendf("\tcoord /= %s;\n", imgInc); fsBuilder->codeAppend("\tvec2 f = fract(coord);\n"); fsBuilder->codeAppendf("\tcoord = (coord - f + vec2(0.5)) * %s;\n", imgInc); fsBuilder->codeAppend("\tvec4 rowColors[4];\n"); for (int y = 0; y < 4; ++y) { for (int x = 0; x < 4; ++x) { SkString coord; coord.printf("coord + %s * vec2(%d, %d)", imgInc, x - 1, y - 1); SkString sampleVar; sampleVar.printf("rowColors[%d]", x); fDomain.sampleTexture(fsBuilder, domain, sampleVar.c_str(), coord, samplers[0]); } fsBuilder->codeAppendf("\tvec4 s%d = %s(%s, f.x, rowColors[0], rowColors[1], rowColors[2], rowColors[3]);\n", y, cubicBlendName.c_str(), coeff); } SkString bicubicColor; bicubicColor.printf("%s(%s, f.y, s0, s1, s2, s3)", cubicBlendName.c_str(), coeff); fsBuilder->codeAppendf("\t%s = %s;\n", outputColor, (GrGLSLExpr4(bicubicColor.c_str()) * GrGLSLExpr4(inputColor)).c_str()); }