Improve GPU blur performance by clearing only when necessary. This gives a
authorsenorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 22 Jul 2011 15:31:14 +0000 (15:31 +0000)
committersenorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 22 Jul 2011 15:31:14 +0000 (15:31 +0000)
1.8X speedup on the Blurs sample, and 2.3X on the BigBlur sample.

We don't need to clear while downsampling, since each step reads only the pixels
written in the previous step.  We can avoid destination clears before
convolution by disabling blending.  We also don't need to clear when upsampling,
since the upsample step also only reads pixels written by the convolution.  The
only clears we then need to do are on each side of the srcRect used for
convolution, and a 1-pixel border for bilinear upsampling.  Since our srcRect is
always offset to (0, 0), we only need to clear on the right and bottom.

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

git-svn-id: http://skia.googlecode.com/svn/trunk@1941 2bbb7eff-a529-9590-31e7-b0007b416f81

gpu/src/GrContext.cpp
src/gpu/SkGpuDevice.cpp

index ef5ad1157de70e21ccc2b2be2e3c51e29fe674ce..b829323b2e21d614ead5bbe4c93593f21826bd02 100644 (file)
@@ -1736,5 +1736,6 @@ void GrContext::convolve(GrTexture* texture,
     fGpu->setSamplerState(0, sampler);
     fGpu->setViewMatrix(GrMatrix::I());
     fGpu->setTexture(0, texture);
+    fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
     fGpu->drawSimpleRect(rect, NULL, 1 << 0);
 }
index c4e0ebecd12ec5d1c0551ebe36da09be5446c4ab..45dac336eaddaa82aec19ed7a7a97a5739b36de1 100644 (file)
@@ -913,9 +913,7 @@ static bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path,
     GrClip oldClip = context->getClip();
     context->setRenderTarget(dstTexture->asRenderTarget());
     context->setClip(srcRect);
-    // FIXME:  could just clear bounds
     context->clear(NULL, 0);
-    GrMatrix transM;
     GrPaint tempPaint;
     tempPaint.reset();
 
@@ -959,9 +957,6 @@ static bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path,
         context->setRenderTarget(dstTexture->asRenderTarget());
         SkRect dstRect(srcRect);
         scaleRect(&dstRect, 0.5f);
-        // Clear out 1 pixel border for linear filtering.
-        // FIXME:  for now, clear everything
-        context->clear(NULL, 0);
         paint.setTexture(0, srcTexture);
         context->drawRectToRect(paint, dstRect, srcRect);
         srcRect = dstRect;
@@ -972,25 +967,41 @@ static bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path,
     float* kernel = kernelStorage.get();
     buildKernel(sigma, kernel, kernelWidth);
 
+    // Clear out a halfWidth to the right of the srcRect to prevent the
+    // X convolution from reading garbage.
+    SkIRect clearRect = SkIRect::MakeXYWH(
+        srcRect.fRight, srcRect.fTop, halfWidth, srcRect.height());
+    context->clear(&clearRect, 0x0);
+
     context->setRenderTarget(dstTexture->asRenderTarget());
-    context->clear(NULL, 0);
     context->convolveInX(srcTexture, srcRect, kernel, kernelWidth);
     SkTSwap(srcTexture, dstTexture);
 
+    // Clear out a halfWidth below the srcRect to prevent the Y
+    // convolution from reading garbage.
+    clearRect = SkIRect::MakeXYWH(
+        srcRect.fLeft, srcRect.fBottom, srcRect.width(), halfWidth);
+    context->clear(&clearRect, 0x0);
+
     context->setRenderTarget(dstTexture->asRenderTarget());
-    context->clear(NULL, 0);
     context->convolveInY(srcTexture, srcRect, kernel, kernelWidth);
     SkTSwap(srcTexture, dstTexture);
 
+    // Clear one pixel to the right and below, to accommodate bilinear
+    // upsampling.
+    clearRect = SkIRect::MakeXYWH(
+        srcRect.fLeft, srcRect.fBottom, srcRect.width() + 1, 1);
+    context->clear(&clearRect, 0x0);
+    clearRect = SkIRect::MakeXYWH(
+        srcRect.fRight, srcRect.fTop, 1, srcRect.height());
+    context->clear(&clearRect, 0x0);
+
     if (scaleFactor > 1) {
         // FIXME:  This should be mitchell, not bilinear.
         paint.getTextureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
         sampleM.setIDiv(srcTexture->width(), srcTexture->height());
         paint.getTextureSampler(0)->setMatrix(sampleM);
         context->setRenderTarget(dstTexture->asRenderTarget());
-        // Clear out 2 pixel border for bicubic filtering.
-        // FIXME:  for now, clear everything
-        context->clear(NULL, 0);
         paint.setTexture(0, srcTexture);
         SkRect dstRect(srcRect);
         scaleRect(&dstRect, scaleFactor);