GPU-based Gaussian blur.

This is a first stab at implementing a GPU-based
Gaussian blur in Ganesh.  The convolution shader is implemented as a new
filtering mode.  There are several known issues:

- no support for blur types other than "normal"
- FBO truncation problem at high zoom values
- uses bilinear for upsampling instead of Mitchell

Review URL:  http://codereview.appspot.com/4645082/



git-svn-id: http://skia.googlecode.com/svn/trunk@1830 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/include/GrContext.h b/gpu/include/GrContext.h
index a8810f9..0c873ee 100644
--- a/gpu/include/GrContext.h
+++ b/gpu/include/GrContext.h
@@ -490,6 +490,21 @@
     void writePixels(int left, int top, int width, int height,
                      GrPixelConfig, const void* buffer, size_t stride);
 
+    /**
+     * Performs a 1D convolution over a rectangle of pixels.  Set
+     * imageIncrement to (1/w, 0) for a convolution in X, (0, 1/h) for a
+     * convolution in Y, where w, h are the texture dimensions.
+     * @param srcTexture      the texture to read from
+     * @param dstRect         the destination rectangle
+     * @param imageIncrement  the displacement between pixel samples
+     * @param kernel          the convolution kernel (kernelWidth elements)
+     * @param kernelWidth     the width of the convolution kernel
+     */
+    void convolveRect(GrTexture* srcTexture,
+                      const SkRect& dstRect,
+                      float imageIncrement[2],
+                      const float* kernel,
+                      int kernelWidth);
     ///////////////////////////////////////////////////////////////////////////
     // Helpers
 
diff --git a/gpu/include/GrSamplerState.h b/gpu/include/GrSamplerState.h
index d10d8c4..c7a4f2b 100644
--- a/gpu/include/GrSamplerState.h
+++ b/gpu/include/GrSamplerState.h
@@ -21,6 +21,8 @@
 #include "GrTypes.h"
 #include "GrMatrix.h"
 
+#define MAX_KERNEL_WIDTH 25
+
 class GrSamplerState {
 public:
     enum Filter {
@@ -39,6 +41,10 @@
          * between texels in x and y spaced 4 texels apart.)
          */
         k4x4Downsample_Filter,
+        /**
+         * Apply a separable convolution kernel.
+         */
+        kConvolution_Filter
     };
 
     /**
@@ -148,6 +154,9 @@
     const GrRect& getTextureDomain() const { return fTextureDomain; }
     bool hasTextureDomain() const {return SkIntToScalar(0) != fTextureDomain.right();}
     Filter getFilter() const { return fFilter; }
+    int getKernelWidth() const { return fKernelWidth; }
+    const float* getKernel() const { return fKernel; }
+    const float* getImageIncrement() const { return fImageIncrement; }
 
     bool isGradient() const {
         return  kRadial_SampleMode == fSampleMode ||
@@ -220,6 +229,19 @@
         fRadial2PosRoot = posRoot;
     }
 
+    void setConvolutionParams(int kernelWidth, const float* kernel, float imageIncrement[2]) {
+        GrAssert(kernelWidth >= 0 && kernelWidth <= MAX_KERNEL_WIDTH);
+        fKernelWidth = kernelWidth;
+        if (NULL != kernel) {
+            memcpy(fKernel, kernel, kernelWidth * sizeof(float));
+        }
+        if (NULL != imageIncrement) {
+            memcpy(fImageIncrement, imageIncrement, sizeof(fImageIncrement));
+        } else {
+            memset(fImageIncrement, 0, sizeof(fImageIncrement));
+        }
+    }
+
     static const GrSamplerState& ClampNoFilter() {
         return gClampNoFilter;
     }
@@ -237,6 +259,11 @@
     GrScalar    fRadial2Radius0;
     bool        fRadial2PosRoot;
 
+    // These are undefined unless fFilter == kConvolution_Filter
+    int         fKernelWidth;
+    float       fKernel[MAX_KERNEL_WIDTH];
+    float       fImageIncrement[2];
+
     static const GrSamplerState gClampNoFilter;
 };