diff options
author | 2012-03-05 20:41:22 +0000 | |
---|---|---|
committer | 2012-03-05 20:41:22 +0000 | |
commit | 3b4dd90282932c9cd695d13f3876f98c9c6d6d5e (patch) | |
tree | 957aa7f82b09d75f2508623744b57fb558356dfd /src/gpu | |
parent | 67ca522bcaa30fb27ffdf49243b97b0d6e3df07d (diff) |
Refactor Gaussian blur and morphology from SkGpuDevice into GrContext.
Review URL: http://codereview.appspot.com/5720060/
git-svn-id: http://skia.googlecode.com/svn/trunk@3327 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/gpu')
-rw-r--r-- | src/gpu/GrContext.cpp | 272 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 222 |
2 files changed, 245 insertions, 249 deletions
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index 2c4a131b38..038f953b8e 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -26,6 +26,8 @@ #define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB) +#define MAX_BLUR_SIGMA 4.0f + // When we're using coverage AA but the blend is incompatible (given gpu // limitations) should we disable AA or draw wrong? #define DISABLE_COVERAGE_AA_FOR_BLEND 1 @@ -218,6 +220,91 @@ void gen_stencil_key_values(const GrStencilBuffer* sb, sb->numSamples(), v); } +void build_kernel(float sigma, float* kernel, int kernelWidth) { + int halfWidth = (kernelWidth - 1) / 2; + float sum = 0.0f; + float denom = 1.0f / (2.0f * sigma * sigma); + for (int i = 0; i < kernelWidth; ++i) { + float x = static_cast<float>(i - halfWidth); + // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian + // is dropped here, since we renormalize the kernel below. + kernel[i] = sk_float_exp(- x * x * denom); + sum += kernel[i]; + } + // Normalize the kernel + float scale = 1.0f / sum; + for (int i = 0; i < kernelWidth; ++i) + kernel[i] *= scale; +} + +void scale_rect(SkRect* rect, float xScale, float yScale) { + rect->fLeft *= xScale; + rect->fTop *= yScale; + rect->fRight *= xScale; + rect->fBottom *= yScale; +} + +float adjust_sigma(float sigma, int *scaleFactor, int *halfWidth, + int *kernelWidth) { + *scaleFactor = 1; + while (sigma > MAX_BLUR_SIGMA) { + *scaleFactor *= 2; + sigma *= 0.5f; + } + *halfWidth = static_cast<int>(ceilf(sigma * 3.0f)); + *kernelWidth = *halfWidth * 2 + 1; + return sigma; +} + +void apply_morphology(GrGpu* gpu, + GrTexture* texture, + const SkRect& rect, + int radius, + GrSamplerState::Filter filter, + GrSamplerState::FilterDirection direction) { + ASSERT_OWNED_RESOURCE(texture); + GrAssert(filter == GrSamplerState::kErode_Filter || + filter == GrSamplerState::kDilate_Filter); + + GrDrawTarget::AutoStateRestore asr(gpu); + GrDrawState* drawState = gpu->drawState(); + GrRenderTarget* target = drawState->getRenderTarget(); + drawState->reset(); + drawState->setRenderTarget(target); + GrMatrix sampleM; + sampleM.setIDiv(texture->width(), texture->height()); + drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode, filter, + sampleM); + drawState->sampler(0)->setMorphologyRadius(radius); + drawState->sampler(0)->setFilterDirection(direction); + drawState->setTexture(0, texture); + gpu->drawSimpleRect(rect, NULL, 1 << 0); +} + +void convolve(GrGpu* gpu, + GrTexture* texture, + const SkRect& rect, + const float* kernel, + int kernelWidth, + GrSamplerState::FilterDirection direction) { + ASSERT_OWNED_RESOURCE(texture); + + GrDrawTarget::AutoStateRestore asr(gpu); + GrDrawState* drawState = gpu->drawState(); + GrRenderTarget* target = drawState->getRenderTarget(); + drawState->reset(); + drawState->setRenderTarget(target); + GrMatrix sampleM; + sampleM.setIDiv(texture->width(), texture->height()); + drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode, + GrSamplerState::kConvolution_Filter, + sampleM); + drawState->sampler(0)->setConvolutionParams(kernelWidth, kernel); + drawState->sampler(0)->setFilterDirection(direction); + drawState->setTexture(0, texture); + gpu->drawSimpleRect(rect, NULL, 1 << 0); +} + } GrContext::TextureCacheEntry GrContext::findAndLockTexture( @@ -2005,52 +2092,151 @@ const GrIndexBuffer* GrContext::getQuadIndexBuffer() const { return fGpu->getQuadIndexBuffer(); } -void GrContext::convolve(GrTexture* texture, - const SkRect& rect, - const float* kernel, - int kernelWidth, - GrSamplerState::FilterDirection direction) { - ASSERT_OWNED_RESOURCE(texture); +GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture, + GrAutoScratchTexture* temp1, + GrAutoScratchTexture* temp2, + const SkRect& rect, + float sigmaX, float sigmaY) { + GrRenderTarget* oldRenderTarget = this->getRenderTarget(); + GrClip oldClip = this->getClip(); + GrTexture* origTexture = srcTexture; + GrAutoMatrix avm(this, GrMatrix::I()); + SkIRect clearRect; + int scaleFactorX, halfWidthX, kernelWidthX; + int scaleFactorY, halfWidthY, kernelWidthY; + sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &halfWidthX, &kernelWidthX); + sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &halfWidthY, &kernelWidthY); + + SkRect srcRect(rect); + scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY); + srcRect.roundOut(); + scale_rect(&srcRect, scaleFactorX, scaleFactorY); + this->setClip(srcRect); - GrDrawTarget::AutoStateRestore asr(fGpu); - GrDrawState* drawState = fGpu->drawState(); - GrRenderTarget* target = drawState->getRenderTarget(); - drawState->reset(); - drawState->setRenderTarget(target); - GrMatrix sampleM; - sampleM.setIDiv(texture->width(), texture->height()); - drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode, - GrSamplerState::kConvolution_Filter, - sampleM); - drawState->sampler(0)->setConvolutionParams(kernelWidth, kernel); - drawState->sampler(0)->setFilterDirection(direction); - drawState->setTexture(0, texture); - fGpu->drawSimpleRect(rect, NULL, 1 << 0); -} + const GrTextureDesc desc = { + kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit, + srcRect.width(), + srcRect.height(), + kRGBA_8888_GrPixelConfig, + {0} // samples + }; -void GrContext::applyMorphology(GrTexture* texture, - const SkRect& rect, - int radius, - GrSamplerState::Filter filter, - GrSamplerState::FilterDirection direction) { - ASSERT_OWNED_RESOURCE(texture); - GrAssert(filter == GrSamplerState::kErode_Filter || - filter == GrSamplerState::kDilate_Filter); + temp1->set(this, desc); + if (temp2) temp2->set(this, desc); + + GrTexture* dstTexture = temp1->texture(); + GrPaint paint; + paint.reset(); + paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter); + + for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) { + paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(), + srcTexture->height()); + this->setRenderTarget(dstTexture->asRenderTarget()); + SkRect dstRect(srcRect); + scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f, + i < scaleFactorY ? 0.5f : 1.0f); + paint.setTexture(0, srcTexture); + this->drawRectToRect(paint, dstRect, srcRect); + srcRect = dstRect; + SkTSwap(srcTexture, dstTexture); + // If temp2 is non-NULL, don't render back to origTexture + if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture(); + } + + if (sigmaX > 0.0f) { + SkAutoTMalloc<float> kernelStorageX(kernelWidthX); + float* kernelX = kernelStorageX.get(); + build_kernel(sigmaX, kernelX, kernelWidthX); + + if (scaleFactorX > 1) { + // Clear out a halfWidth to the right of the srcRect to prevent the + // X convolution from reading garbage. + clearRect = SkIRect::MakeXYWH( + srcRect.fRight, srcRect.fTop, halfWidthX, srcRect.height()); + this->clear(&clearRect, 0x0); + } - GrDrawTarget::AutoStateRestore asr(fGpu); - GrDrawState* drawState = fGpu->drawState(); - GrRenderTarget* target = drawState->getRenderTarget(); - drawState->reset(); - drawState->setRenderTarget(target); - GrMatrix sampleM; - sampleM.setIDiv(texture->width(), texture->height()); - drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode, - filter, - sampleM); - drawState->sampler(0)->setMorphologyRadius(radius); - drawState->sampler(0)->setFilterDirection(direction); - drawState->setTexture(0, texture); - fGpu->drawSimpleRect(rect, NULL, 1 << 0); + this->setRenderTarget(dstTexture->asRenderTarget()); + convolve(fGpu, srcTexture, srcRect, kernelX, kernelWidthX, + GrSamplerState::kX_FilterDirection); + SkTSwap(srcTexture, dstTexture); + if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture(); + } + + if (sigmaY > 0.0f) { + SkAutoTMalloc<float> kernelStorageY(kernelWidthY); + float* kernelY = kernelStorageY.get(); + build_kernel(sigmaY, kernelY, kernelWidthY); + + if (scaleFactorY > 1 || sigmaX > 0.0f) { + // Clear out a halfWidth below the srcRect to prevent the Y + // convolution from reading garbage. + clearRect = SkIRect::MakeXYWH( + srcRect.fLeft, srcRect.fBottom, srcRect.width(), halfWidthY); + this->clear(&clearRect, 0x0); + } + + this->setRenderTarget(dstTexture->asRenderTarget()); + convolve(fGpu, srcTexture, srcRect, kernelY, kernelWidthY, + GrSamplerState::kY_FilterDirection); + SkTSwap(srcTexture, dstTexture); + if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture(); + } + + if (scaleFactorX > 1 || scaleFactorY > 1) { + // Clear one pixel to the right and below, to accommodate bilinear + // upsampling. + clearRect = SkIRect::MakeXYWH( + srcRect.fLeft, srcRect.fBottom, srcRect.width() + 1, 1); + this->clear(&clearRect, 0x0); + clearRect = SkIRect::MakeXYWH( + srcRect.fRight, srcRect.fTop, 1, srcRect.height()); + this->clear(&clearRect, 0x0); + // FIXME: This should be mitchell, not bilinear. + paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter); + paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(), + srcTexture->height()); + this->setRenderTarget(dstTexture->asRenderTarget()); + paint.setTexture(0, srcTexture); + SkRect dstRect(srcRect); + scale_rect(&dstRect, scaleFactorX, scaleFactorY); + this->drawRectToRect(paint, dstRect, srcRect); + srcRect = dstRect; + SkTSwap(srcTexture, dstTexture); + } + this->setRenderTarget(oldRenderTarget); + this->setClip(oldClip); + return srcTexture; +} + +GrTexture* GrContext::applyMorphology(GrTexture* srcTexture, + const GrRect& rect, + GrTexture* temp1, GrTexture* temp2, + GrSamplerState::Filter filter, + SkISize radius) { + GrRenderTarget* oldRenderTarget = this->getRenderTarget(); + GrAutoMatrix avm(this, GrMatrix::I()); + GrClip oldClip = this->getClip(); + this->setClip(GrRect::MakeWH(srcTexture->width(), srcTexture->height())); + if (radius.fWidth > 0) { + this->setRenderTarget(temp1->asRenderTarget()); + apply_morphology(fGpu, srcTexture, rect, radius.fWidth, filter, + GrSamplerState::kX_FilterDirection); + SkIRect clearRect = SkIRect::MakeXYWH(rect.fLeft, rect.fBottom, + rect.width(), radius.fHeight); + this->clear(&clearRect, 0x0); + srcTexture = temp1; + } + if (radius.fHeight > 0) { + this->setRenderTarget(temp2->asRenderTarget()); + apply_morphology(fGpu, srcTexture, rect, radius.fHeight, filter, + GrSamplerState::kY_FilterDirection); + srcTexture = temp2; + } + this->setRenderTarget(oldRenderTarget); + this->setClip(oldClip); + return srcTexture; } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index 0f4dea0859..c27314a772 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -719,198 +719,6 @@ static GrPathFill skToGrFillType(SkPath::FillType fillType) { } } -static GrTexture* applyMorphology(GrContext* context, GrTexture* texture, - const GrRect& srcRect, - GrTexture* temp1, GrTexture* temp2, - GrSamplerState::Filter filter, - SkISize radius) { - GrRenderTarget* oldRenderTarget = context->getRenderTarget(); - GrAutoMatrix avm(context, GrMatrix::I()); - GrClip oldClip = context->getClip(); - context->setClip(GrRect::MakeWH(texture->width(), texture->height())); - if (radius.fWidth > 0) { - context->setRenderTarget(temp1->asRenderTarget()); - context->applyMorphology(texture, srcRect, radius.fWidth, filter, - GrSamplerState::kX_FilterDirection); - SkIRect clearRect = SkIRect::MakeXYWH( - srcRect.fLeft, srcRect.fBottom, - srcRect.width(), radius.fHeight); - context->clear(&clearRect, 0x0); - texture = temp1; - } - if (radius.fHeight > 0) { - context->setRenderTarget(temp2->asRenderTarget()); - context->applyMorphology(texture, srcRect, radius.fHeight, filter, - GrSamplerState::kY_FilterDirection); - texture = temp2; - } - context->setRenderTarget(oldRenderTarget); - context->setClip(oldClip); - return texture; -} - -static void buildKernel(float sigma, float* kernel, int kernelWidth) { - int halfWidth = (kernelWidth - 1) / 2; - float sum = 0.0f; - float denom = 1.0f / (2.0f * sigma * sigma); - for (int i = 0; i < kernelWidth; ++i) { - float x = static_cast<float>(i - halfWidth); - // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian - // is dropped here, since we renormalize the kernel below. - kernel[i] = sk_float_exp(- x * x * denom); - sum += kernel[i]; - } - // Normalize the kernel - float scale = 1.0f / sum; - for (int i = 0; i < kernelWidth; ++i) - kernel[i] *= scale; -} - -static void scaleRect(SkRect* rect, float xScale, float yScale) { - rect->fLeft *= xScale; - rect->fTop *= yScale; - rect->fRight *= xScale; - rect->fBottom *= yScale; -} - -static float adjustSigma(float sigma, int *scaleFactor, int *halfWidth, - int *kernelWidth) { - *scaleFactor = 1; - while (sigma > MAX_BLUR_SIGMA) { - *scaleFactor *= 2; - sigma *= 0.5f; - } - *halfWidth = static_cast<int>(ceilf(sigma * 3.0f)); - *kernelWidth = *halfWidth * 2 + 1; - return sigma; -} - -// Apply a Gaussian blur to srcTexture by sigmaX and sigmaY, within the given -// rect. -// temp1 and temp2 are used for allocation of intermediate textures. -// If temp2 is non-NULL, srcTexture will be untouched, and the return -// value will be either temp1 or temp2. -// If temp2 is NULL, srcTexture will be overwritten with intermediate -// results, and the return value will either be temp1 or srcTexture. -static GrTexture* gaussianBlur(GrContext* context, GrTexture* srcTexture, - GrAutoScratchTexture* temp1, - GrAutoScratchTexture* temp2, - const SkRect& rect, - float sigmaX, float sigmaY) { - - GrRenderTarget* oldRenderTarget = context->getRenderTarget(); - GrClip oldClip = context->getClip(); - GrTexture* origTexture = srcTexture; - GrAutoMatrix avm(context, GrMatrix::I()); - SkIRect clearRect; - int scaleFactorX, halfWidthX, kernelWidthX; - int scaleFactorY, halfWidthY, kernelWidthY; - sigmaX = adjustSigma(sigmaX, &scaleFactorX, &halfWidthX, &kernelWidthX); - sigmaY = adjustSigma(sigmaY, &scaleFactorY, &halfWidthY, &kernelWidthY); - - SkRect srcRect(rect); - scaleRect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY); - srcRect.roundOut(); - scaleRect(&srcRect, scaleFactorX, scaleFactorY); - context->setClip(srcRect); - - const GrTextureDesc desc = { - kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit, - srcRect.width(), - srcRect.height(), - kRGBA_8888_GrPixelConfig, - {0} // samples - }; - - temp1->set(context, desc); - if (temp2) temp2->set(context, desc); - - GrTexture* dstTexture = temp1->texture(); - GrPaint paint; - paint.reset(); - paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter); - - for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) { - paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(), - srcTexture->height()); - context->setRenderTarget(dstTexture->asRenderTarget()); - SkRect dstRect(srcRect); - scaleRect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f, - i < scaleFactorY ? 0.5f : 1.0f); - paint.setTexture(0, srcTexture); - context->drawRectToRect(paint, dstRect, srcRect); - srcRect = dstRect; - SkTSwap(srcTexture, dstTexture); - // If temp2 is non-NULL, don't render back to origTexture - if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture(); - } - - if (sigmaX > 0.0f) { - SkAutoTMalloc<float> kernelStorageX(kernelWidthX); - float* kernelX = kernelStorageX.get(); - buildKernel(sigmaX, kernelX, kernelWidthX); - - if (scaleFactorX > 1) { - // Clear out a halfWidth to the right of the srcRect to prevent the - // X convolution from reading garbage. - clearRect = SkIRect::MakeXYWH( - srcRect.fRight, srcRect.fTop, halfWidthX, srcRect.height()); - context->clear(&clearRect, 0x0); - } - - context->setRenderTarget(dstTexture->asRenderTarget()); - context->convolve(srcTexture, srcRect, kernelX, kernelWidthX, - GrSamplerState::kX_FilterDirection); - SkTSwap(srcTexture, dstTexture); - if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture(); - } - - if (sigmaY > 0.0f) { - SkAutoTMalloc<float> kernelStorageY(kernelWidthY); - float* kernelY = kernelStorageY.get(); - buildKernel(sigmaY, kernelY, kernelWidthY); - - if (scaleFactorY > 1 || sigmaX > 0.0f) { - // Clear out a halfWidth below the srcRect to prevent the Y - // convolution from reading garbage. - clearRect = SkIRect::MakeXYWH( - srcRect.fLeft, srcRect.fBottom, srcRect.width(), halfWidthY); - context->clear(&clearRect, 0x0); - } - - context->setRenderTarget(dstTexture->asRenderTarget()); - context->convolve(srcTexture, srcRect, kernelY, kernelWidthY, - GrSamplerState::kY_FilterDirection); - SkTSwap(srcTexture, dstTexture); - if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture(); - } - - if (scaleFactorX > 1 || scaleFactorY > 1) { - // 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); - // FIXME: This should be mitchell, not bilinear. - paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter); - paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(), - srcTexture->height()); - context->setRenderTarget(dstTexture->asRenderTarget()); - paint.setTexture(0, srcTexture); - SkRect dstRect(srcRect); - scaleRect(&dstRect, scaleFactorX, scaleFactorY); - context->drawRectToRect(paint, dstRect, srcRect); - srcRect = dstRect; - SkTSwap(srcTexture, dstTexture); - } - context->setRenderTarget(oldRenderTarget); - context->setClip(oldClip); - return srcTexture; -} - static bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path, SkMaskFilter* filter, const SkMatrix& matrix, const SkRegion& clip, SkBounder* bounder, @@ -995,9 +803,10 @@ static bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path, // If we're doing a normal blur, we can clobber the pathTexture in the // gaussianBlur. Otherwise, we need to save it for later compositing. bool isNormalBlur = blurType == SkMaskFilter::kNormal_BlurType; - GrTexture* blurTexture = gaussianBlur(context, pathTexture, - &temp1, isNormalBlur ? NULL : &temp2, - srcRect, sigma, sigma); + GrTexture* blurTexture = context->gaussianBlur(pathTexture, + &temp1, + isNormalBlur ? NULL : &temp2, + srcRect, sigma, sigma); if (!isNormalBlur) { GrPaint paint; @@ -1538,11 +1347,10 @@ void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, SkISize radius; if (NULL != imageFilter && imageFilter->asABlur(&blurSize)) { GrAutoScratchTexture temp1, temp2; - GrTexture* blurTexture = gaussianBlur(fContext, - texture, &temp1, &temp2, - GrRect::MakeWH(w, h), - blurSize.width(), - blurSize.height()); + GrTexture* blurTexture = fContext->gaussianBlur(texture, &temp1, &temp2, + GrRect::MakeWH(w, h), + blurSize.width(), + blurSize.height()); texture = blurTexture; grPaint.setTexture(kBitmapTextureIdx, texture); } else if (NULL != imageFilter && imageFilter->asADilate(&radius)) { @@ -1554,9 +1362,10 @@ void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, {0} // samples }; GrAutoScratchTexture temp1(fContext, desc), temp2(fContext, desc); - texture = applyMorphology(fContext, texture, GrRect::MakeWH(w, h), - temp1.texture(), temp2.texture(), - GrSamplerState::kDilate_Filter, radius); + texture = fContext->applyMorphology(texture, GrRect::MakeWH(w, h), + temp1.texture(), temp2.texture(), + GrSamplerState::kDilate_Filter, + radius); grPaint.setTexture(kBitmapTextureIdx, texture); } else if (NULL != imageFilter && imageFilter->asAnErode(&radius)) { const GrTextureDesc desc = { @@ -1567,9 +1376,10 @@ void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, {0} // samples }; GrAutoScratchTexture temp1(fContext, desc), temp2(fContext, desc); - texture = applyMorphology(fContext, texture, GrRect::MakeWH(w, h), - temp1.texture(), temp2.texture(), - GrSamplerState::kErode_Filter, radius); + texture = fContext->applyMorphology(texture, GrRect::MakeWH(w, h), + temp1.texture(), temp2.texture(), + GrSamplerState::kErode_Filter, + radius); grPaint.setTexture(kBitmapTextureIdx, texture); } else { grPaint.setTexture(kBitmapTextureIdx, texture); |