1ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt/*
2ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt * Copyright 2014 Google Inc.
3ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt *
4ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt * Use of this source code is governed by a BSD-style license that can be
5ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt * found in the LICENSE file.
6ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt */
730ba436f04e61d4505fb854d5fc56079636e0788joshualitt#include "gl/builders/GrGLProgramBuilder.h"
8ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt#include "GrMatrixConvolutionEffect.h"
9b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt#include "gl/GrGLProcessor.h"
10ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt#include "gl/GrGLSL.h"
11ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt#include "gl/GrGLTexture.h"
12b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt#include "GrTBackendProcessorFactory.h"
13ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt
14b0a8a377f832c59cee939ad721e1f87d378b7142joshualittclass GrGLMatrixConvolutionEffect : public GrGLFragmentProcessor {
15ac9779234ef7a8cf3d791ab7690ef8c388662836joshualittpublic:
16b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GrGLMatrixConvolutionEffect(const GrBackendProcessorFactory& factory,
17b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                const GrProcessor&);
1830ba436f04e61d4505fb854d5fc56079636e0788joshualitt    virtual void emitCode(GrGLProgramBuilder*,
19b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                          const GrFragmentProcessor&,
20b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                          const GrProcessorKey&,
21ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                          const char* outputColor,
22ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                          const char* inputColor,
23ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                          const TransformedCoordsArray&,
24ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                          const TextureSamplerArray&) SK_OVERRIDE;
25ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt
26b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    static inline void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder*);
27ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt
28b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
29ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt
30ac9779234ef7a8cf3d791ab7690ef8c388662836joshualittprivate:
317510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    typedef GrGLProgramDataManager::UniformHandle UniformHandle;
325ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt    SkISize                     fKernelSize;
335ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt    bool                        fConvolveAlpha;
34ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt
355ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt    UniformHandle               fBoundsUni;
365ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt    UniformHandle               fKernelUni;
375ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt    UniformHandle               fImageIncrementUni;
385ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt    UniformHandle               fKernelOffsetUni;
395ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt    UniformHandle               fGainUni;
405ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt    UniformHandle               fBiasUni;
415ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt    GrTextureDomain::GLDomain   fDomain;
42ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt
43b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    typedef GrGLFragmentProcessor INHERITED;
44ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt};
45ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt
46b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGrGLMatrixConvolutionEffect::GrGLMatrixConvolutionEffect(const GrBackendProcessorFactory& factory,
47b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                         const GrProcessor& processor)
48ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    : INHERITED(factory) {
49b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    const GrMatrixConvolutionEffect& m = processor.cast<GrMatrixConvolutionEffect>();
50ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    fKernelSize = m.kernelSize();
51ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    fConvolveAlpha = m.convolveAlpha();
52ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt}
53ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt
5430ba436f04e61d4505fb854d5fc56079636e0788joshualittvoid GrGLMatrixConvolutionEffect::emitCode(GrGLProgramBuilder* builder,
55b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                           const GrFragmentProcessor& fp,
56b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                           const GrProcessorKey& key,
57ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                                           const char* outputColor,
58ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                                           const char* inputColor,
59ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                                           const TransformedCoordsArray& coords,
60ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                                           const TextureSamplerArray& samplers) {
61ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    sk_ignore_unused_variable(inputColor);
62b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    const GrTextureDomain& domain = fp.cast<GrMatrixConvolutionEffect>().domain();
6330ba436f04e61d4505fb854d5fc56079636e0788joshualitt
6430ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fBoundsUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
65ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                                     kVec4f_GrSLType, "Bounds");
6630ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fImageIncrementUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
67ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                                             kVec2f_GrSLType, "ImageIncrement");
6830ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fKernelUni = builder->addUniformArray(GrGLProgramBuilder::kFragment_Visibility,
695ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt                                          kFloat_GrSLType,
705ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt                                          "Kernel",
715ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt                                          fKernelSize.width() * fKernelSize.height());
7230ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fKernelOffsetUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
735ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt                                           kVec2f_GrSLType, "KernelOffset");
7430ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fGainUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
75ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                                   kFloat_GrSLType, "Gain");
7630ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fBiasUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
77ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                                   kFloat_GrSLType, "Bias");
78ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt
79ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    const char* kernelOffset = builder->getUniformCStr(fKernelOffsetUni);
80ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
81ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    const char* kernel = builder->getUniformCStr(fKernelUni);
82ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    const char* gain = builder->getUniformCStr(fGainUni);
83ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    const char* bias = builder->getUniformCStr(fBiasUni);
84ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    int kWidth = fKernelSize.width();
85ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    int kHeight = fKernelSize.height();
86ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt
8730ba436f04e61d4505fb854d5fc56079636e0788joshualitt    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
8830ba436f04e61d4505fb854d5fc56079636e0788joshualitt    SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0);
8930ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppend("vec4 sum = vec4(0, 0, 0, 0);");
9030ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppendf("vec2 coord = %s - %s * %s;", coords2D.c_str(), kernelOffset,
915ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt                           imgInc);
9230ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppend("vec4 c;");
935ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt
945ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt    for (int y = 0; y < kHeight; y++) {
955ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt        for (int x = 0; x < kWidth; x++) {
9630ba436f04e61d4505fb854d5fc56079636e0788joshualitt            GrGLShaderBuilder::ShaderBlock block(fsBuilder);
9730ba436f04e61d4505fb854d5fc56079636e0788joshualitt            fsBuilder->codeAppendf("float k = %s[%d * %d + %d];", kernel, y, kWidth, x);
985ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt            SkString coord;
995ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt            coord.printf("coord + vec2(%d, %d) * %s", x, y, imgInc);
10030ba436f04e61d4505fb854d5fc56079636e0788joshualitt            fDomain.sampleTexture(fsBuilder, domain, "c", coord, samplers[0]);
1015ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt            if (!fConvolveAlpha) {
10230ba436f04e61d4505fb854d5fc56079636e0788joshualitt                fsBuilder->codeAppend("c.rgb /= c.a;");
1035ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt            }
10430ba436f04e61d4505fb854d5fc56079636e0788joshualitt            fsBuilder->codeAppend("sum += c * k;");
1055ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt        }
106ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    }
107ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    if (fConvolveAlpha) {
10830ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppendf("%s = sum * %s + %s;", outputColor, gain, bias);
10930ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppendf("%s.rgb = clamp(%s.rgb, 0.0, %s.a);",
1105ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt                               outputColor, outputColor, outputColor);
111ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    } else {
11230ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fDomain.sampleTexture(fsBuilder, domain, "c", coords2D, samplers[0]);
11330ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppendf("%s.a = c.a;", outputColor);
11430ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppendf("%s.rgb = sum.rgb * %s + %s;", outputColor, gain, bias);
11530ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppendf("%s.rgb *= %s.a;", outputColor, outputColor);
116ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    }
1175acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt
1185acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt    SkString modulate;
1195acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt    GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
12030ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppend(modulate.c_str());
121ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt}
122ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt
123b0a8a377f832c59cee939ad721e1f87d378b7142joshualittvoid GrGLMatrixConvolutionEffect::GenKey(const GrProcessor& processor,
124b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                         const GrGLCaps&, GrProcessorKeyBuilder* b) {
125b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    const GrMatrixConvolutionEffect& m = processor.cast<GrMatrixConvolutionEffect>();
1265ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt    SkASSERT(m.kernelSize().width() <= 0x7FFF && m.kernelSize().height() <= 0xFFFF);
1275ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt    uint32_t key = m.kernelSize().width() << 16 | m.kernelSize().height();
1285ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt    key |= m.convolveAlpha() ? 1 << 31 : 0;
129ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    b->add32(key);
1305ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt    b->add32(GrTextureDomain::GLDomain::DomainKey(m.domain()));
131ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt}
132ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt
1337510b224e52b9518a8ddf7418db0e9c258f79539kkinnunenvoid GrGLMatrixConvolutionEffect::setData(const GrGLProgramDataManager& pdman,
134b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                          const GrProcessor& processor) {
135b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    const GrMatrixConvolutionEffect& conv = processor.cast<GrMatrixConvolutionEffect>();
136ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    GrTexture& texture = *conv.texture(0);
137ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    // the code we generated was for a specific kernel size
138ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    SkASSERT(conv.kernelSize() == fKernelSize);
139ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    float imageIncrement[2];
140ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    float ySign = texture.origin() == kTopLeft_GrSurfaceOrigin ? 1.0f : -1.0f;
141ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    imageIncrement[0] = 1.0f / texture.width();
142ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    imageIncrement[1] = ySign / texture.height();
1437510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    pdman.set2fv(fImageIncrementUni, 1, imageIncrement);
1447510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    pdman.set2fv(fKernelOffsetUni, 1, conv.kernelOffset());
1457510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    pdman.set1fv(fKernelUni, fKernelSize.width() * fKernelSize.height(), conv.kernel());
1467510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    pdman.set1f(fGainUni, conv.gain());
1477510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    pdman.set1f(fBiasUni, conv.bias());
1487510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    fDomain.setData(pdman, conv.domain(), texture.origin());
149ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt}
150ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt
151ac9779234ef7a8cf3d791ab7690ef8c388662836joshualittGrMatrixConvolutionEffect::GrMatrixConvolutionEffect(GrTexture* texture,
152ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                                                     const SkIRect& bounds,
153ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                                                     const SkISize& kernelSize,
154ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                                                     const SkScalar* kernel,
155ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                                                     SkScalar gain,
156ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                                                     SkScalar bias,
157ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                                                     const SkIPoint& kernelOffset,
1585ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt                                                     GrTextureDomain::Mode tileMode,
159ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                                                     bool convolveAlpha)
1606267f81f3d60ce144ab2b09ea369420984d5c9d9bsalomon  : INHERITED(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture)),
161ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    fKernelSize(kernelSize),
162ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    fGain(SkScalarToFloat(gain)),
163ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    fBias(SkScalarToFloat(bias) / 255.0f),
1645ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt    fConvolveAlpha(convolveAlpha),
1655ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt    fDomain(GrTextureDomain::MakeTexelDomain(texture, bounds), tileMode) {
166ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    for (int i = 0; i < kernelSize.width() * kernelSize.height(); i++) {
167ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt        fKernel[i] = SkScalarToFloat(kernel[i]);
168ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    }
169ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    fKernelOffset[0] = static_cast<float>(kernelOffset.x());
170ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    fKernelOffset[1] = static_cast<float>(kernelOffset.y());
171ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt}
172ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt
173ac9779234ef7a8cf3d791ab7690ef8c388662836joshualittGrMatrixConvolutionEffect::~GrMatrixConvolutionEffect() {
174ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt}
175ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt
176b0a8a377f832c59cee939ad721e1f87d378b7142joshualittconst GrBackendFragmentProcessorFactory& GrMatrixConvolutionEffect::getFactory() const {
177b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    return GrTBackendFragmentProcessorFactory<GrMatrixConvolutionEffect>::getInstance();
178ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt}
179ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt
180b0a8a377f832c59cee939ad721e1f87d378b7142joshualittbool GrMatrixConvolutionEffect::onIsEqual(const GrProcessor& sBase) const {
18149586bec7383d4ccb81f85f8e2dc4162e2d4f6a8joshualitt    const GrMatrixConvolutionEffect& s = sBase.cast<GrMatrixConvolutionEffect>();
182ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    return this->texture(0) == s.texture(0) &&
183ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt           fKernelSize == s.kernelSize() &&
184ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt           !memcmp(fKernel, s.kernel(),
185ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                   fKernelSize.width() * fKernelSize.height() * sizeof(float)) &&
186ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt           fGain == s.gain() &&
187ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt           fBias == s.bias() &&
188ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt           fKernelOffset == s.kernelOffset() &&
1895ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt           fConvolveAlpha == s.convolveAlpha() &&
1905ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt           fDomain == s.domain();
191ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt}
192ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt
1935acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt// Static function to create a 2D convolution
194b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGrFragmentProcessor*
195b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGrMatrixConvolutionEffect::CreateGaussian(GrTexture* texture,
196b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                          const SkIRect& bounds,
197b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                          const SkISize& kernelSize,
198b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                          SkScalar gain,
199b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                          SkScalar bias,
200b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                          const SkIPoint& kernelOffset,
201b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                          GrTextureDomain::Mode tileMode,
202b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                          bool convolveAlpha,
203b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                          SkScalar sigmaX,
204b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                          SkScalar sigmaY) {
2055acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt    float kernel[MAX_KERNEL_SIZE];
2065acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt    int width = kernelSize.width();
2075acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt    int height = kernelSize.height();
2085acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt    SkASSERT(width * height <= MAX_KERNEL_SIZE);
2095acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt    float sum = 0.0f;
2105acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt    float sigmaXDenom = 1.0f / (2.0f * SkScalarToFloat(SkScalarSquare(sigmaX)));
2115acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt    float sigmaYDenom = 1.0f / (2.0f * SkScalarToFloat(SkScalarSquare(sigmaY)));
2125acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt    int xRadius = width / 2;
2135acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt    int yRadius = height / 2;
2145acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt    for (int x = 0; x < width; x++) {
2155acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt      float xTerm = static_cast<float>(x - xRadius);
2165acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt      xTerm = xTerm * xTerm * sigmaXDenom;
2175acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt      for (int y = 0; y < height; y++) {
2185acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt        float yTerm = static_cast<float>(y - yRadius);
2195acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt        float xyTerm = sk_float_exp(-(xTerm + yTerm * yTerm * sigmaYDenom));
2205acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt        // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian
2215acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt       // is dropped here, since we renormalize the kernel below.
2225acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt        kernel[y * width + x] = xyTerm;
2235acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt        sum += xyTerm;
2245acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt      }
2255acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt    }
2265acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt    // Normalize the kernel
2275acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt    float scale = 1.0f / sum;
2285acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt    for (int i = 0; i < width * height; ++i) {
2295acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt        kernel[i] *= scale;
2305acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt    }
2315acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt    return SkNEW_ARGS(GrMatrixConvolutionEffect, (texture,
2325acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt                                                  bounds,
2335acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt                                                  kernelSize,
2345acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt                                                  kernel,
2355acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt                                                  gain,
2365acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt                                                  bias,
2375acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt                                                  kernelOffset,
2385acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt                                                  tileMode,
2395acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt                                                  convolveAlpha));
2405acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt}
2415acfea789d39106dbc706c6ee85cd8f027fce3edjoshualitt
242b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrMatrixConvolutionEffect);
243ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt
244b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGrFragmentProcessor* GrMatrixConvolutionEffect::TestCreate(SkRandom* random,
245b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                           GrContext* context,
246b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                           const GrDrawTargetCaps&,
247b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                           GrTexture* textures[]) {
248b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
249b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                      GrProcessorUnitTest::kAlphaTextureIdx;
250ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    int width = random->nextRangeU(1, MAX_KERNEL_SIZE);
251ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    int height = random->nextRangeU(1, MAX_KERNEL_SIZE / width);
252ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    SkISize kernelSize = SkISize::Make(width, height);
253ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    SkAutoTDeleteArray<SkScalar> kernel(new SkScalar[width * height]);
254ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    for (int i = 0; i < width * height; i++) {
255ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt        kernel.get()[i] = random->nextSScalar1();
256ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    }
257ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    SkScalar gain = random->nextSScalar1();
258ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    SkScalar bias = random->nextSScalar1();
259ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    SkIPoint kernelOffset = SkIPoint::Make(random->nextRangeU(0, kernelSize.width()),
260ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                                           random->nextRangeU(0, kernelSize.height()));
261ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    SkIRect bounds = SkIRect::MakeXYWH(random->nextRangeU(0, textures[texIdx]->width()),
262ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                                       random->nextRangeU(0, textures[texIdx]->height()),
263ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                                       random->nextRangeU(0, textures[texIdx]->width()),
264ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                                       random->nextRangeU(0, textures[texIdx]->height()));
2655ae5fc59b27a48711e514b3ede548b228e393e9bjoshualitt    GrTextureDomain::Mode tileMode = static_cast<GrTextureDomain::Mode>(random->nextRangeU(0, 2));
266ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    bool convolveAlpha = random->nextBool();
267ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt    return GrMatrixConvolutionEffect::Create(textures[texIdx],
268ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                                             bounds,
269ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                                             kernelSize,
270ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                                             kernel.get(),
271ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                                             gain,
272ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                                             bias,
273ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                                             kernelOffset,
274ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                                             tileMode,
275ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt                                             convolveAlpha);
276ac9779234ef7a8cf3d791ab7690ef8c388662836joshualitt}
277