Small optimization for convolution shader: only apply the bounds check in direction of convolution, not both. This requires generating different versions of the shader depending on direction.

R=robertphillips@google.com

Review URL: https://codereview.chromium.org/20789003

git-svn-id: http://skia.googlecode.com/svn/trunk@10417 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/effects/GrConvolutionEffect.cpp b/src/gpu/effects/GrConvolutionEffect.cpp
index 3fa1cb9..e7fb8e5 100644
--- a/src/gpu/effects/GrConvolutionEffect.cpp
+++ b/src/gpu/effects/GrConvolutionEffect.cpp
@@ -33,13 +33,15 @@
 
 private:
     int width() const { return Gr1DKernelEffect::WidthFromRadius(fRadius); }
-    bool useCropRect() const { return fUseCropRect; }
+    bool useBounds() const { return fUseBounds; }
+    Gr1DKernelEffect::Direction direction() const { return fDirection; }
 
     int                 fRadius;
-    bool                fUseCropRect;
+    bool                fUseBounds;
+    Gr1DKernelEffect::Direction    fDirection;
     UniformHandle       fKernelUni;
     UniformHandle       fImageIncrementUni;
-    UniformHandle       fCropRectUni;
+    UniformHandle       fBoundsUni;
     GrGLEffectMatrix    fEffectMatrix;
 
     typedef GrGLEffect INHERITED;
@@ -50,11 +52,12 @@
     : INHERITED(factory)
     , fKernelUni(kInvalidUniformHandle)
     , fImageIncrementUni(kInvalidUniformHandle)
-    , fCropRectUni(kInvalidUniformHandle)
+    , fBoundsUni(kInvalidUniformHandle)
     , fEffectMatrix(drawEffect.castEffect<GrConvolutionEffect>().coordsType()) {
     const GrConvolutionEffect& c = drawEffect.castEffect<GrConvolutionEffect>();
     fRadius = c.radius();
-    fUseCropRect = c.useCropRect();
+    fUseBounds = c.useBounds();
+    fDirection = c.direction();
 }
 
 void GrGLConvolutionEffect::emitCode(GrGLShaderBuilder* builder,
@@ -67,9 +70,9 @@
     fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, &coords);
     fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
                                              kVec2f_GrSLType, "ImageIncrement");
-    if (this->useCropRect()) {
-        fCropRectUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
-                                           kVec4f_GrSLType, "CropRect");
+    if (this->useBounds()) {
+        fBoundsUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
+                                         kVec2f_GrSLType, "Bounds");
     }
     fKernelUni = builder->addUniformArray(GrGLShaderBuilder::kFragment_ShaderType,
                                           kFloat_GrSLType, "Kernel", this->width());
@@ -90,10 +93,11 @@
         kernel.appendArrayAccess(index.c_str(), &kernelIndex);
         builder->fsCodeAppendf("\t\t%s += ", outputColor);
         builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, samplers[0], "coord");
-        if (this->useCropRect()) {
-            const char* cropRect = builder->getUniformCStr(fCropRectUni);
-            builder->fsCodeAppendf(" * float(coord.x >= %s.x && coord.x <= %s.y && coord.y >= %s.z && coord.y <= %s.w)",
-            cropRect, cropRect, cropRect, cropRect);
+        if (this->useBounds()) {
+            const char* bounds = builder->getUniformCStr(fBoundsUni);
+            const char* component = this->direction() == Gr1DKernelEffect::kY_Direction ? "y" : "x";
+            builder->fsCodeAppendf(" * float(coord.%s >= %s.x && coord.%s <= %s.y)",
+                component, bounds, component, bounds);
         }
         builder->fsCodeAppendf(" * %s;\n", kernelIndex.c_str());
         builder->fsCodeAppendf("\t\tcoord += %s;\n", imgInc);
@@ -123,15 +127,14 @@
             GrCrash("Unknown filter direction.");
     }
     uman.set2fv(fImageIncrementUni, 0, 1, imageIncrement);
-    if (conv.useCropRect()) {
-        float c[4];
-        memcpy(c, conv.cropRect(), sizeof(c));
-        if (texture.origin() != kTopLeft_GrSurfaceOrigin) {
-            float tmp = 1.0f - c[2];
-            c[2] = 1.0f - c[3];
-            c[3] = tmp;
+    if (conv.useBounds()) {
+        const float* bounds = conv.bounds();
+        if (Gr1DKernelEffect::kY_Direction == conv.direction() &&
+            texture.origin() != kTopLeft_GrSurfaceOrigin) {
+            uman.set2f(fBoundsUni, 1.0f - bounds[1], 1.0f - bounds[0]);
+        } else {
+            uman.set2f(fBoundsUni, bounds[0], bounds[1]);
         }
-        uman.set4fv(fCropRectUni, 0, 1, c);
     }
     uman.set1fv(fKernelUni, 0, this->width(), conv.kernel());
     fEffectMatrix.setData(uman, conv.getMatrix(), drawEffect, conv.texture(0));
@@ -140,8 +143,12 @@
 GrGLEffect::EffectKey GrGLConvolutionEffect::GenKey(const GrDrawEffect& drawEffect,
                                                     const GrGLCaps&) {
     const GrConvolutionEffect& conv = drawEffect.castEffect<GrConvolutionEffect>();
-    EffectKey key = conv.radius() << 1;
-    key |= conv.useCropRect() ? 0x1 : 0x0;
+    EffectKey key = conv.radius();
+    key <<= 2;
+    if (conv.useBounds()) {
+        key |= 0x2;
+        key |= GrConvolutionEffect::kY_Direction == conv.direction() ? 0x1 : 0x0;
+    }
     key <<= GrGLEffectMatrix::kKeyBits;
     EffectKey matrixKey = GrGLEffectMatrix::GenKey(conv.getMatrix(),
                                                    drawEffect,
@@ -156,25 +163,25 @@
                                          Direction direction,
                                          int radius,
                                          const float* kernel,
-                                         bool useCropRect,
-                                         float cropRect[4])
-    : Gr1DKernelEffect(texture, direction, radius), fUseCropRect(useCropRect) {
+                                         bool useBounds,
+                                         float bounds[2])
+    : Gr1DKernelEffect(texture, direction, radius), fUseBounds(useBounds) {
     GrAssert(radius <= kMaxKernelRadius);
     GrAssert(NULL != kernel);
     int width = this->width();
     for (int i = 0; i < width; i++) {
         fKernel[i] = kernel[i];
     }
-    memcpy(fCropRect, cropRect, sizeof(fCropRect));
+    memcpy(fBounds, bounds, sizeof(fBounds));
 }
 
 GrConvolutionEffect::GrConvolutionEffect(GrTexture* texture,
                                          Direction direction,
                                          int radius,
                                          float gaussianSigma,
-                                         bool useCropRect,
-                                         float cropRect[4])
-    : Gr1DKernelEffect(texture, direction, radius), fUseCropRect(useCropRect) {
+                                         bool useBounds,
+                                         float bounds[2])
+    : Gr1DKernelEffect(texture, direction, radius), fUseBounds(useBounds) {
     GrAssert(radius <= kMaxKernelRadius);
     int width = this->width();
 
@@ -192,7 +199,7 @@
     for (int i = 0; i < width; ++i) {
         fKernel[i] *= scale;
     }
-    memcpy(fCropRect, cropRect, sizeof(fCropRect));
+    memcpy(fBounds, bounds, sizeof(fBounds));
 }
 
 GrConvolutionEffect::~GrConvolutionEffect() {
@@ -207,7 +214,8 @@
     return (this->texture(0) == s.texture(0) &&
             this->radius() == s.radius() &&
             this->direction() == s.direction() &&
-            0 == memcmp(fCropRect, s.fCropRect, sizeof(fCropRect)) &&
+            this->useBounds() == s.useBounds() &&
+            0 == memcmp(fBounds, s.fBounds, sizeof(fBounds)) &&
             0 == memcmp(fKernel, s.fKernel, this->width() * sizeof(float)));
 }
 
@@ -224,19 +232,19 @@
     Direction dir = random->nextBool() ? kX_Direction : kY_Direction;
     int radius = random->nextRangeU(1, kMaxKernelRadius);
     float kernel[kMaxKernelRadius];
-    float cropRect[4];
     for (int i = 0; i < kMaxKernelRadius; ++i) {
         kernel[i] = random->nextSScalar1();
     }
-    for (int i = 0; i < 4; ++i) {
-        cropRect[i] = random->nextF();
+    float bounds[2];
+    for (int i = 0; i < 2; ++i) {
+        bounds[i] = random->nextF();
     }
 
-    bool useCropRect = random->nextBool();
+    bool useBounds = random->nextBool();
     return GrConvolutionEffect::Create(textures[texIdx],
                                        dir,
                                        radius,
                                        kernel,
-                                       useCropRect,
-                                       cropRect);
+                                       useBounds,
+                                       bounds);
 }