void GrGLConvolutionEffect::emitCode(EmitArgs& args) { const GrConvolutionEffect& ce = args.fFp.cast<GrConvolutionEffect>(); GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; fImageIncrementUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, kVec2f_GrSLType, kDefault_GrSLPrecision, "ImageIncrement"); if (ce.useBounds()) { fBoundsUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, kVec2f_GrSLType, kDefault_GrSLPrecision, "Bounds"); } int width = Gr1DKernelEffect::WidthFromRadius(ce.radius()); fKernelUni = uniformHandler->addUniformArray(GrGLSLUniformHandler::kFragment_Visibility, kFloat_GrSLType, kDefault_GrSLPrecision, "Kernel", width); GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; SkString coords2D = fragBuilder->ensureFSCoords2D(args.fCoords, 0); fragBuilder->codeAppendf("%s = vec4(0, 0, 0, 0);", args.fOutputColor); const GrGLSLShaderVar& kernel = uniformHandler->getUniformVariable(fKernelUni); const char* imgInc = uniformHandler->getUniformCStr(fImageIncrementUni); fragBuilder->codeAppendf("vec2 coord = %s - %d.0 * %s;", coords2D.c_str(), ce.radius(), imgInc); // Manually unroll loop because some drivers don't; yields 20-30% speedup. for (int i = 0; i < width; i++) { SkString index; SkString kernelIndex; index.appendS32(i); kernel.appendArrayAccess(index.c_str(), &kernelIndex); if (ce.useBounds()) { // We used to compute a bool indicating whether we're in bounds or not, cast it to a // float, and then mul weight*texture_sample by the float. However, the Adreno 430 seems // to have a bug that caused corruption. const char* bounds = uniformHandler->getUniformCStr(fBoundsUni); const char* component = ce.direction() == Gr1DKernelEffect::kY_Direction ? "y" : "x"; fragBuilder->codeAppendf("if (coord.%s >= %s.x && coord.%s <= %s.y) {", component, bounds, component, bounds); } fragBuilder->codeAppendf("\t\t%s += ", args.fOutputColor); fragBuilder->appendTextureLookup(args.fSamplers[0], "coord"); fragBuilder->codeAppendf(" * %s;\n", kernelIndex.c_str()); if (ce.useBounds()) { fragBuilder->codeAppend("}"); } fragBuilder->codeAppendf("\t\tcoord += %s;\n", imgInc); } SkString modulate; GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor); fragBuilder->codeAppend(modulate.c_str()); }
void emitCode(EmitArgs& args) override { GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; fragBuilder->codeAppendf("vec2 c = %s;", fragBuilder->ensureFSCoords2D(args.fCoords, 0).c_str()); fragBuilder->codeAppend("vec2 r = mod(c, vec2(20.0));"); fragBuilder->codeAppend("vec4 color = vec4(0.5*sin(c.x / 15.0) + 0.5," "0.5*cos((c.x + c.y) / 15.0) + 0.5," "(r.x + r.y) / 20.0," "distance(r, vec2(15.0)) / 20.0 + 0.2);"); fragBuilder->codeAppendf("color.rgb *= color.a;" "%s = color * %s;", args.fOutputColor, GrGLSLExpr4(args.fInputColor).c_str()); }
void GrGLMagnifierEffect::emitCode(EmitArgs& args) { GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; fOffsetVar = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, kVec2f_GrSLType, kDefault_GrSLPrecision, "Offset"); fInvZoomVar = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, kVec2f_GrSLType, kDefault_GrSLPrecision, "InvZoom"); fInvInsetVar = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, kVec2f_GrSLType, kDefault_GrSLPrecision, "InvInset"); fBoundsVar = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, kVec4f_GrSLType, kDefault_GrSLPrecision, "Bounds"); GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; SkString coords2D = fragBuilder->ensureFSCoords2D(args.fCoords, 0); fragBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str()); fragBuilder->codeAppendf("\t\tvec2 zoom_coord = %s + %s * %s;\n", uniformHandler->getUniformCStr(fOffsetVar), coords2D.c_str(), uniformHandler->getUniformCStr(fInvZoomVar)); const char* bounds = uniformHandler->getUniformCStr(fBoundsVar); fragBuilder->codeAppendf("\t\tvec2 delta = (coord - %s.xy) * %s.zw;\n", bounds, bounds); fragBuilder->codeAppendf("\t\tdelta = min(delta, vec2(1.0, 1.0) - delta);\n"); fragBuilder->codeAppendf("\t\tdelta = delta * %s;\n", uniformHandler->getUniformCStr(fInvInsetVar)); fragBuilder->codeAppend("\t\tfloat weight = 0.0;\n"); fragBuilder->codeAppend("\t\tif (delta.s < 2.0 && delta.t < 2.0) {\n"); fragBuilder->codeAppend("\t\t\tdelta = vec2(2.0, 2.0) - delta;\n"); fragBuilder->codeAppend("\t\t\tfloat dist = length(delta);\n"); fragBuilder->codeAppend("\t\t\tdist = max(2.0 - dist, 0.0);\n"); fragBuilder->codeAppend("\t\t\tweight = min(dist * dist, 1.0);\n"); fragBuilder->codeAppend("\t\t} else {\n"); fragBuilder->codeAppend("\t\t\tvec2 delta_squared = delta * delta;\n"); fragBuilder->codeAppend("\t\t\tweight = min(min(delta_squared.x, delta_squared.y), 1.0);\n"); fragBuilder->codeAppend("\t\t}\n"); fragBuilder->codeAppend("\t\tvec2 mix_coord = mix(coord, zoom_coord, weight);\n"); fragBuilder->codeAppend("\t\tvec4 output_color = "); fragBuilder->appendTextureLookup(args.fSamplers[0], "mix_coord"); fragBuilder->codeAppend(";\n"); fragBuilder->codeAppendf("\t\t%s = output_color;", args.fOutputColor); SkString modulate; GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor); fragBuilder->codeAppend(modulate.c_str()); }
void GrGLDisplacementMapEffect::emitCode(EmitArgs& args) { const GrTextureDomain& domain = args.fFp.cast<GrDisplacementMapEffect>().domain(); fScaleUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility, kVec2f_GrSLType, kDefault_GrSLPrecision, "Scale"); const char* scaleUni = args.fBuilder->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. GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; fragBuilder->codeAppendf("\t\tvec4 %s = ", dColor); fragBuilder->appendTextureLookup(args.fSamplers[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 (fXChannelSelector) { 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 (fYChannelSelector) { 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.fGLSLCaps, domain, args.fOutputColor, SkString(cCoords), args.fSamplers[1]); fragBuilder->codeAppend(";\n"); }
void GrGLMorphologyEffect::emitCode(EmitArgs& args) { GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; fPixelSizeUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, kFloat_GrSLType, kDefault_GrSLPrecision, "PixelSize"); const char* pixelSizeInc = uniformHandler->getUniformCStr(fPixelSizeUni); fRangeUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, kVec2f_GrSLType, kDefault_GrSLPrecision, "Range"); const char* range = uniformHandler->getUniformCStr(fRangeUni); GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; SkString coords2D = fragBuilder->ensureFSCoords2D(args.fCoords, 0); const char* func; switch (fType) { 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 (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; fragBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str()); // coord.x -= radius * pixelSize; fragBuilder->codeAppendf("\t\tcoord.%s -= %d.0 * %s; \n", dir, fRadius, pixelSizeInc); if (fUseRange) { // 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.fSamplers[0], "coord"); fragBuilder->codeAppend(");\n"); // coord.x += pixelSize; fragBuilder->codeAppendf("\t\t\tcoord.%s += %s;\n", dir, pixelSizeInc); if (fUseRange) { // 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 GrGLBicubicEffect::emitCode(EmitArgs& args) { const GrTextureDomain& domain = args.fFp.cast<GrBicubicEffect>().domain(); GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; fCoefficientsUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kMat44f_GrSLType, kDefault_GrSLPrecision, "Coefficients"); fImageIncrementUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kVec2f_GrSLType, kDefault_GrSLPrecision, "ImageIncrement"); const char* imgInc = uniformHandler->getUniformCStr(fImageIncrementUni); const char* coeff = uniformHandler->getUniformCStr(fCoefficientsUni); SkString cubicBlendName; static const GrGLSLShaderVar gCubicBlendArgs[] = { GrGLSLShaderVar("coefficients", kMat44f_GrSLType), GrGLSLShaderVar("t", kFloat_GrSLType), GrGLSLShaderVar("c0", kVec4f_GrSLType), GrGLSLShaderVar("c1", kVec4f_GrSLType), GrGLSLShaderVar("c2", kVec4f_GrSLType), GrGLSLShaderVar("c3", kVec4f_GrSLType), }; GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; SkString coords2D = fragBuilder->ensureFSCoords2D(args.fCoords, 0); fragBuilder->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); fragBuilder->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. fragBuilder->codeAppendf("\tcoord /= %s;\n", imgInc); fragBuilder->codeAppend("\tvec2 f = fract(coord);\n"); fragBuilder->codeAppendf("\tcoord = (coord - f + vec2(0.5)) * %s;\n", imgInc); fragBuilder->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(fragBuilder, args.fUniformHandler, args.fGLSLCaps, domain, sampleVar.c_str(), coord, args.fSamplers[0]); } fragBuilder->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); fragBuilder->codeAppendf("\t%s = %s;\n", args.fOutputColor, (GrGLSLExpr4(bicubicColor.c_str()) * GrGLSLExpr4(args.fInputColor)).c_str()); }
void GrGLMatrixConvolutionEffect::emitCode(EmitArgs& args) { const GrTextureDomain& domain = args.fFp.cast<GrMatrixConvolutionEffect>().domain(); GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; fImageIncrementUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, kVec2f_GrSLType, kDefault_GrSLPrecision, "ImageIncrement"); fKernelUni = uniformHandler->addUniformArray(GrGLSLUniformHandler::kFragment_Visibility, kFloat_GrSLType, kDefault_GrSLPrecision, "Kernel", fKernelSize.width() * fKernelSize.height()); fKernelOffsetUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, kVec2f_GrSLType, kDefault_GrSLPrecision, "KernelOffset"); fGainUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, kFloat_GrSLType, kDefault_GrSLPrecision, "Gain"); fBiasUni = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, kFloat_GrSLType, kDefault_GrSLPrecision, "Bias"); const char* kernelOffset = uniformHandler->getUniformCStr(fKernelOffsetUni); const char* imgInc = uniformHandler->getUniformCStr(fImageIncrementUni); const char* kernel = uniformHandler->getUniformCStr(fKernelUni); const char* gain = uniformHandler->getUniformCStr(fGainUni); const char* bias = uniformHandler->getUniformCStr(fBiasUni); int kWidth = fKernelSize.width(); int kHeight = fKernelSize.height(); GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; SkString coords2D = fragBuilder->ensureFSCoords2D(args.fCoords, 0); fragBuilder->codeAppend("vec4 sum = vec4(0, 0, 0, 0);"); fragBuilder->codeAppendf("vec2 coord = %s - %s * %s;", coords2D.c_str(), kernelOffset, imgInc); fragBuilder->codeAppend("vec4 c;"); for (int y = 0; y < kHeight; y++) { for (int x = 0; x < kWidth; x++) { GrGLSLShaderBuilder::ShaderBlock block(fragBuilder); fragBuilder->codeAppendf("float k = %s[%d * %d + %d];", kernel, y, kWidth, x); SkString coord; coord.printf("coord + vec2(%d, %d) * %s", x, y, imgInc); fDomain.sampleTexture(fragBuilder, uniformHandler, args.fGLSLCaps, domain, "c", coord, args.fSamplers[0]); if (!fConvolveAlpha) { fragBuilder->codeAppend("c.rgb /= c.a;"); fragBuilder->codeAppend("c.rgb = clamp(c.rgb, 0.0, 1.0);"); } fragBuilder->codeAppend("sum += c * k;"); } } if (fConvolveAlpha) { fragBuilder->codeAppendf("%s = sum * %s + %s;", args.fOutputColor, gain, bias); fragBuilder->codeAppendf("%s.rgb = clamp(%s.rgb, 0.0, %s.a);", args.fOutputColor, args.fOutputColor, args.fOutputColor); } else { fDomain.sampleTexture(fragBuilder, uniformHandler, args.fGLSLCaps, domain, "c", coords2D, args.fSamplers[0]); fragBuilder->codeAppendf("%s.a = c.a;", args.fOutputColor); fragBuilder->codeAppendf("%s.rgb = sum.rgb * %s + %s;", args.fOutputColor, gain, bias); fragBuilder->codeAppendf("%s.rgb *= %s.a;", args.fOutputColor, args.fOutputColor); } SkString modulate; GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor); fragBuilder->codeAppend(modulate.c_str()); }