void GrGLBicubicEffect::emitCode(EmitArgs& args) { const GrTextureDomain& domain = args.fFp.cast<GrBicubicEffect>().domain(); fCoefficientsUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kMat44f_GrSLType, kDefault_GrSLPrecision, "Coefficients"); fImageIncrementUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kVec2f_GrSLType, kDefault_GrSLPrecision, "ImageIncrement"); const char* imgInc = args.fBuilder->getUniformCStr(fImageIncrementUni); const char* coeff = args.fBuilder->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), }; GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder(); SkString coords2D = fsBuilder->ensureFSCoords2D(args.fCoords, 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, args.fSamplers[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", args.fOutputColor,(GrGLSLExpr4(bicubicColor.c_str()) * GrGLSLExpr4(args.fInputColor)).c_str()); }
void GrGLDisplacementMapEffect::setData(const GrGLProgramDataManager& pdman, const GrProcessor& proc) { const GrDisplacementMapEffect& displacementMap = proc.cast<GrDisplacementMapEffect>(); GrTexture* colorTex = displacementMap.texture(1); SkScalar scaleX = SkScalarDiv(displacementMap.scale().fX, SkIntToScalar(colorTex->width())); SkScalar scaleY = SkScalarDiv(displacementMap.scale().fY, SkIntToScalar(colorTex->height())); pdman.set2f(fScaleUni, SkScalarToFloat(scaleX), colorTex->origin() == kTopLeft_GrSurfaceOrigin ? SkScalarToFloat(scaleY) : SkScalarToFloat(-scaleY)); fGLDomain.setData(pdman, displacementMap.domain(), colorTex->origin()); }
void GrGLBicubicEffect::onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& processor) { const GrBicubicEffect& bicubicEffect = processor.cast<GrBicubicEffect>(); const GrTexture& texture = *processor.texture(0); float imageIncrement[2]; imageIncrement[0] = 1.0f / texture.width(); imageIncrement[1] = 1.0f / texture.height(); pdman.set2fv(fImageIncrementUni, 1, imageIncrement); pdman.setMatrix4f(fCoefficientsUni, bicubicEffect.coefficients()); fDomain.setData(pdman, bicubicEffect.domain(), texture.origin()); }
void GrGLBicubicEffect::onSetData(const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor) { const GrBicubicEffect& bicubicEffect = processor.cast<GrBicubicEffect>(); GrSurfaceProxy* proxy = processor.textureSampler(0).proxy(); GrTexture* texture = proxy->peekTexture(); float imageIncrement[2]; imageIncrement[0] = 1.0f / texture->width(); imageIncrement[1] = 1.0f / texture->height(); pdman.set2fv(fImageIncrementUni, 1, imageIncrement); fDomain.setData(pdman, bicubicEffect.domain(), proxy); }
void GrGLBicubicEffect::onSetData(const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor) { const GrBicubicEffect& bicubicEffect = processor.cast<GrBicubicEffect>(); GrTexture* texture = processor.textureSampler(0).peekTexture(); float imageIncrement[2]; imageIncrement[0] = 1.0f / texture->width(); imageIncrement[1] = 1.0f / texture->height(); pdman.set2fv(fImageIncrementUni, 1, imageIncrement); fDomain.setData(pdman, bicubicEffect.domain(), texture); if (SkToBool(bicubicEffect.colorSpaceXform())) { fColorSpaceHelper.setData(pdman, bicubicEffect.colorSpaceXform()); } }
void GrGLMatrixConvolutionEffect::onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& processor) { const GrMatrixConvolutionEffect& conv = processor.cast<GrMatrixConvolutionEffect>(); GrTexture& texture = *conv.texture(0); // the code we generated was for a specific kernel size SkASSERT(conv.kernelSize() == fKernelSize); float imageIncrement[2]; float ySign = texture.origin() == kTopLeft_GrSurfaceOrigin ? 1.0f : -1.0f; imageIncrement[0] = 1.0f / texture.width(); imageIncrement[1] = ySign / texture.height(); pdman.set2fv(fImageIncrementUni, 1, imageIncrement); pdman.set2fv(fKernelOffsetUni, 1, conv.kernelOffset()); pdman.set1fv(fKernelUni, fKernelSize.width() * fKernelSize.height(), conv.kernel()); pdman.set1f(fGainUni, conv.gain()); pdman.set1f(fBiasUni, conv.bias()); fDomain.setData(pdman, conv.domain(), texture.origin()); }
void GrGLMatrixConvolutionEffect::onSetData(const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor) { const GrMatrixConvolutionEffect& conv = processor.cast<GrMatrixConvolutionEffect>(); GrSurfaceProxy* proxy = conv.textureSampler(0).proxy(); GrTexture* texture = proxy->priv().peekTexture(); float imageIncrement[2]; float ySign = proxy->origin() == kTopLeft_GrSurfaceOrigin ? 1.0f : -1.0f; imageIncrement[0] = 1.0f / texture->width(); imageIncrement[1] = ySign / texture->height(); pdman.set2fv(fImageIncrementUni, 1, imageIncrement); pdman.set2fv(fKernelOffsetUni, 1, conv.kernelOffset()); int kernelCount = conv.kernelSize().width() * conv.kernelSize().height(); int arrayCount = (kernelCount + 3) / 4; SkASSERT(4 * arrayCount >= kernelCount); pdman.set4fv(fKernelUni, arrayCount, conv.kernel()); pdman.set1f(fGainUni, conv.gain()); pdman.set1f(fBiasUni, conv.bias()); fDomain.setData(pdman, conv.domain(), proxy); }
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 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 GrGLBicubicEffect::emitCode(EmitArgs& args) { const GrBicubicEffect& bicubicEffect = args.fFp.cast<GrBicubicEffect>(); GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; fImageIncrementUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kVec2f_GrSLType, kDefault_GrSLPrecision, "ImageIncrement"); const char* imgInc = uniformHandler->getUniformCStr(fImageIncrementUni); fColorSpaceHelper.emitCode(uniformHandler, bicubicEffect.colorSpaceXform()); GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; SkString coords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]); /* * Filter weights come from Don Mitchell & Arun Netravali's 'Reconstruction Filters in Computer * Graphics', ACM SIGGRAPH Computer Graphics 22, 4 (Aug. 1988). * ACM DL: http://dl.acm.org/citation.cfm?id=378514 * Free : http://www.cs.utexas.edu/users/fussell/courses/cs384g/lectures/mitchell/Mitchell.pdf * * The authors define a family of cubic filters with two free parameters (B and C): * * { (12 - 9B - 6C)|x|^3 + (-18 + 12B + 6C)|x|^2 + (6 - 2B) if |x| < 1 * k(x) = 1/6 { (-B - 6C)|x|^3 + (6B + 30C)|x|^2 + (-12B - 48C)|x| + (8B + 24C) if 1 <= |x| < 2 * { 0 otherwise * * Various well-known cubic splines can be generated, and the authors select (1/3, 1/3) as their * favorite overall spline - this is now commonly known as the Mitchell filter, and is the * source of the specific weights below. * * This is GLSL, so the matrix is column-major (transposed from standard matrix notation). */ fragBuilder->codeAppend("mat4 kMitchellCoefficients = mat4(" " 1.0 / 18.0, 16.0 / 18.0, 1.0 / 18.0, 0.0 / 18.0," "-9.0 / 18.0, 0.0 / 18.0, 9.0 / 18.0, 0.0 / 18.0," "15.0 / 18.0, -36.0 / 18.0, 27.0 / 18.0, -6.0 / 18.0," "-7.0 / 18.0, 21.0 / 18.0, -21.0 / 18.0, 7.0 / 18.0);"); fragBuilder->codeAppendf("vec2 coord = %s - %s * vec2(0.5);", 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("coord /= %s;", imgInc); fragBuilder->codeAppend("vec2 f = fract(coord);"); fragBuilder->codeAppendf("coord = (coord - f + vec2(0.5)) * %s;", imgInc); fragBuilder->codeAppend("vec4 wx = kMitchellCoefficients * vec4(1.0, f.x, f.x * f.x, f.x * f.x * f.x);"); fragBuilder->codeAppend("vec4 wy = kMitchellCoefficients * vec4(1.0, f.y, f.y * f.y, f.y * f.y * f.y);"); fragBuilder->codeAppend("vec4 rowColors[4];"); 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.fShaderCaps, bicubicEffect.domain(), sampleVar.c_str(), coord, args.fTexSamplers[0]); } fragBuilder->codeAppendf( "vec4 s%d = wx.x * rowColors[0] + wx.y * rowColors[1] + wx.z * rowColors[2] + wx.w * rowColors[3];", y); } SkString bicubicColor("(wy.x * s0 + wy.y * s1 + wy.z * s2 + wy.w * s3)"); if (fColorSpaceHelper.isValid()) { SkString xformedColor; fragBuilder->appendColorGamutXform(&xformedColor, bicubicColor.c_str(), &fColorSpaceHelper); bicubicColor.swap(xformedColor); } fragBuilder->codeAppendf("%s = %s * %s;", args.fOutputColor, bicubicColor.c_str(), args.fInputColor); }
void GrGLMatrixConvolutionEffect::emitCode(EmitArgs& args) { const GrMatrixConvolutionEffect& mce = args.fFp.cast<GrMatrixConvolutionEffect>(); const GrTextureDomain& domain = mce.domain(); int kWidth = mce.kernelSize().width(); int kHeight = mce.kernelSize().height(); int arrayCount = (kWidth * kHeight + 3) / 4; SkASSERT(4 * arrayCount >= kWidth * kHeight); GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; fImageIncrementUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType, "ImageIncrement"); fKernelUni = uniformHandler->addUniformArray(kFragment_GrShaderFlag, kHalf4_GrSLType, "Kernel", arrayCount); fKernelOffsetUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType, "KernelOffset"); fGainUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType, "Gain"); fBiasUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType, "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); GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; SkString coords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]); fragBuilder->codeAppend("half4 sum = half4(0, 0, 0, 0);"); fragBuilder->codeAppendf("float2 coord = %s - %s * %s;", coords2D.c_str(), kernelOffset, imgInc); fragBuilder->codeAppend("half4 c;"); const char* kVecSuffix[4] = { ".x", ".y", ".z", ".w" }; for (int y = 0; y < kHeight; y++) { for (int x = 0; x < kWidth; x++) { GrGLSLShaderBuilder::ShaderBlock block(fragBuilder); int offset = y*kWidth + x; fragBuilder->codeAppendf("half k = %s[%d]%s;", kernel, offset / 4, kVecSuffix[offset & 0x3]); SkString coord; coord.printf("coord + half2(%d, %d) * %s", x, y, imgInc); fDomain.sampleTexture(fragBuilder, uniformHandler, args.fShaderCaps, domain, "c", coord, args.fTexSamplers[0]); if (!mce.convolveAlpha()) { fragBuilder->codeAppend("c.rgb /= c.a;"); fragBuilder->codeAppend("c.rgb = clamp(c.rgb, 0.0, 1.0);"); } fragBuilder->codeAppend("sum += c * k;"); } } if (mce.convolveAlpha()) { fragBuilder->codeAppendf("%s = sum * %s + %s;", args.fOutputColor, gain, bias); fragBuilder->codeAppendf("%s.a = clamp(%s.a, 0, 1);", args.fOutputColor, args.fOutputColor); fragBuilder->codeAppendf("%s.rgb = clamp(%s.rgb, 0.0, %s.a);", args.fOutputColor, args.fOutputColor, args.fOutputColor); } else { fDomain.sampleTexture(fragBuilder, uniformHandler, args.fShaderCaps, domain, "c", coords2D, args.fTexSamplers[0]); fragBuilder->codeAppendf("%s.a = c.a;", args.fOutputColor); fragBuilder->codeAppendf("%s.rgb = clamp(sum.rgb * %s + %s, 0, 1);", args.fOutputColor, gain, bias); fragBuilder->codeAppendf("%s.rgb *= %s.a;", args.fOutputColor, args.fOutputColor); } fragBuilder->codeAppendf("%s *= %s;\n", args.fOutputColor, args.fInputColor); }
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()); }