bool SkBicubicImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm, SkBitmap* result, SkIPoint* offset) { SkBitmap srcBM; if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, ctm, &srcBM, offset)) { return false; } GrTexture* srcTexture = srcBM.getTexture(); GrContext* context = srcTexture->getContext(); SkRect dstRect = SkRect::MakeWH(srcBM.width() * fScale.fWidth, srcBM.height() * fScale.fHeight); GrTextureDesc desc; desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; desc.fWidth = SkScalarCeilToInt(dstRect.width()); desc.fHeight = SkScalarCeilToInt(dstRect.height()); desc.fConfig = kSkia8888_GrPixelConfig; GrAutoScratchTexture ast(context, desc); SkAutoTUnref<GrTexture> dst(ast.detach()); if (!dst) { return false; } GrContext::AutoRenderTarget art(context, dst->asRenderTarget()); GrPaint paint; paint.addColorEffect(GrBicubicEffect::Create(srcTexture, fCoefficients))->unref(); SkRect srcRect; srcBM.getBounds(&srcRect); context->drawRectToRect(paint, dstRect, srcRect); return SkImageFilterUtils::WrapTexture(dst, desc.fWidth, desc.fHeight, result); }
bool SkXfermodeImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { SkBitmap background = src; SkIPoint backgroundOffset = SkIPoint::Make(0, 0); if (getInput(0) && !getInput(0)->getInputResultGPU(proxy, src, ctx, &background, &backgroundOffset)) { return onFilterImage(proxy, src, ctx, result, offset); } GrTexture* backgroundTex = background.getTexture(); SkBitmap foreground = src; SkIPoint foregroundOffset = SkIPoint::Make(0, 0); if (getInput(1) && !getInput(1)->getInputResultGPU(proxy, src, ctx, &foreground, &foregroundOffset)) { return onFilterImage(proxy, src, ctx, result, offset); } GrTexture* foregroundTex = foreground.getTexture(); GrContext* context = foregroundTex->getContext(); GrEffect* xferEffect = NULL; GrTextureDesc desc; desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; desc.fWidth = src.width(); desc.fHeight = src.height(); desc.fConfig = kSkia8888_GrPixelConfig; GrAutoScratchTexture ast(context, desc); SkAutoTUnref<GrTexture> dst(ast.detach()); GrContext::AutoRenderTarget art(context, dst->asRenderTarget()); if (!fMode || !fMode->asNewEffect(&xferEffect, backgroundTex)) { // canFilterImageGPU() should've taken care of this SkASSERT(false); return false; } SkMatrix foregroundMatrix = GrEffect::MakeDivByTextureWHMatrix(foregroundTex); foregroundMatrix.preTranslate(SkIntToScalar(backgroundOffset.fX-foregroundOffset.fX), SkIntToScalar(backgroundOffset.fY-foregroundOffset.fY)); SkRect srcRect; src.getBounds(&srcRect); GrPaint paint; paint.addColorTextureEffect(foregroundTex, foregroundMatrix); paint.addColorEffect(xferEffect)->unref(); context->drawRect(paint, srcRect); offset->fX = backgroundOffset.fX; offset->fY = backgroundOffset.fY; WrapTexture(dst, src.width(), src.height(), result); return true; }
bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm, SkBitmap* result, SkIPoint* offset) { #if SK_SUPPORT_GPU SkBitmap input; SkASSERT(fInputCount == 1); if (!SkImageFilterUtils::GetInputResultGPU(this->getInput(0), proxy, src, ctm, &input, offset)) { return false; } GrTexture* srcTexture = input.getTexture(); SkIRect bounds; src.getBounds(&bounds); if (!this->applyCropRect(&bounds, ctm)) { return false; } SkRect srcRect = SkRect::Make(bounds); SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); GrContext* context = srcTexture->getContext(); GrTextureDesc desc; desc.fFlags = kRenderTarget_GrTextureFlagBit, desc.fWidth = bounds.width(); desc.fHeight = bounds.height(); desc.fConfig = kRGBA_8888_GrPixelConfig; GrAutoScratchTexture dst(context, desc); GrContext::AutoMatrix am; am.setIdentity(context); GrContext::AutoRenderTarget art(context, dst.texture()->asRenderTarget()); GrContext::AutoClip acs(context, dstRect); GrEffectRef* effect; SkMatrix matrix(ctm); matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); this->asNewEffect(&effect, srcTexture, matrix, bounds); SkASSERT(effect); SkAutoUnref effectRef(effect); GrPaint paint; paint.addColorEffect(effect); context->drawRectToRect(paint, dstRect, srcRect); SkAutoTUnref<GrTexture> resultTex(dst.detach()); SkImageFilterUtils::WrapTexture(resultTex, bounds.width(), bounds.height(), result); offset->fX += bounds.left(); offset->fY += bounds.top(); return true; #else return false; #endif }
static void convolve_gaussian_pass(GrContext* context, const SkRect& srcRect, const SkRect& dstRect, GrTexture* texture, Gr1DKernelEffect::Direction direction, int radius, float sigma, bool useBounds, float bounds[2]) { GrPaint paint; paint.reset(); SkAutoTUnref<GrEffectRef> conv(GrConvolutionEffect::CreateGaussian( texture, direction, radius, sigma, useBounds, bounds)); paint.reset(); paint.addColorEffect(conv); context->drawRectToRect(paint, dstRect, srcRect); }
bool SkXfermodeImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm, SkBitmap* result, SkIPoint* offset) { SkBitmap background; SkIPoint backgroundOffset = SkIPoint::Make(0, 0); if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, ctm, &background, &backgroundOffset)) { return false; } GrTexture* backgroundTex = background.getTexture(); SkBitmap foreground; SkIPoint foregroundOffset = SkIPoint::Make(0, 0); if (!SkImageFilterUtils::GetInputResultGPU(getInput(1), proxy, src, ctm, &foreground, &foregroundOffset)) { return false; } GrTexture* foregroundTex = foreground.getTexture(); GrContext* context = foregroundTex->getContext(); GrEffectRef* xferEffect = NULL; GrTextureDesc desc; desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; desc.fWidth = src.width(); desc.fHeight = src.height(); desc.fConfig = kSkia8888_GrPixelConfig; GrAutoScratchTexture ast(context, desc); SkAutoTUnref<GrTexture> dst(ast.detach()); GrContext::AutoRenderTarget art(context, dst->asRenderTarget()); SkXfermode::Coeff sm, dm; if (!SkXfermode::AsNewEffectOrCoeff(fMode, &xferEffect, &sm, &dm, backgroundTex)) { return false; } SkMatrix foregroundMatrix = GrEffect::MakeDivByTextureWHMatrix(foregroundTex); foregroundMatrix.preTranslate(SkIntToScalar(backgroundOffset.fX-foregroundOffset.fX), SkIntToScalar(backgroundOffset.fY-foregroundOffset.fY)); SkRect srcRect; src.getBounds(&srcRect); if (NULL != xferEffect) { GrPaint paint; paint.addColorTextureEffect(foregroundTex, foregroundMatrix); paint.addColorEffect(xferEffect)->unref(); context->drawRect(paint, srcRect); } else { GrPaint backgroundPaint; SkMatrix backgroundMatrix = GrEffect::MakeDivByTextureWHMatrix(backgroundTex); backgroundPaint.addColorTextureEffect(backgroundTex, backgroundMatrix); context->drawRect(backgroundPaint, srcRect); GrPaint foregroundPaint; foregroundPaint.setBlendFunc(sk_blend_to_grblend(sm), sk_blend_to_grblend(dm)); foregroundPaint.addColorTextureEffect(foregroundTex, foregroundMatrix); context->drawRect(foregroundPaint, srcRect); } offset->fX += backgroundOffset.fX; offset->fY += backgroundOffset.fY; return SkImageFilterUtils::WrapTexture(dst, src.width(), src.height(), result); }
GrTexture* GaussianBlur(GrContext* context, GrTexture* srcTexture, bool canClobberSrc, const SkRect& rect, bool cropToRect, float sigmaX, float sigmaY) { SkASSERT(NULL != context); GrContext::AutoRenderTarget art(context); GrContext::AutoMatrix am; am.setIdentity(context); SkIRect clearRect; int scaleFactorX, radiusX; int scaleFactorY, radiusY; sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &radiusX); sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &radiusY); SkRect srcRect(rect); scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY); srcRect.roundOut(); scale_rect(&srcRect, static_cast<float>(scaleFactorX), static_cast<float>(scaleFactorY)); GrContext::AutoClip acs(context, SkRect::MakeWH(srcRect.width(), srcRect.height())); SkASSERT(kBGRA_8888_GrPixelConfig == srcTexture->config() || kRGBA_8888_GrPixelConfig == srcTexture->config() || kAlpha_8_GrPixelConfig == srcTexture->config()); GrTextureDesc desc; desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; desc.fWidth = SkScalarFloorToInt(srcRect.width()); desc.fHeight = SkScalarFloorToInt(srcRect.height()); desc.fConfig = srcTexture->config(); GrAutoScratchTexture temp1, temp2; GrTexture* dstTexture = temp1.set(context, desc); GrTexture* tempTexture = canClobberSrc ? srcTexture : temp2.set(context, desc); if (NULL == dstTexture || NULL == tempTexture) { return NULL; } for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) { GrPaint paint; SkMatrix matrix; matrix.setIDiv(srcTexture->width(), srcTexture->height()); context->setRenderTarget(dstTexture->asRenderTarget()); SkRect dstRect(srcRect); if (cropToRect && i == 1) { dstRect.offset(-dstRect.fLeft, -dstRect.fTop); SkRect domain; matrix.mapRect(&domain, rect); domain.inset(i < scaleFactorX ? SK_ScalarHalf / srcTexture->width() : 0.0f, i < scaleFactorY ? SK_ScalarHalf / srcTexture->height() : 0.0f); SkAutoTUnref<GrEffectRef> effect(GrTextureDomainEffect::Create( srcTexture, matrix, domain, GrTextureDomainEffect::kDecal_WrapMode, GrTextureParams::kBilerp_FilterMode)); paint.addColorEffect(effect); } else { GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_FilterMode); paint.addColorTextureEffect(srcTexture, matrix, params); } scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f, i < scaleFactorY ? 0.5f : 1.0f); context->drawRectToRect(paint, dstRect, srcRect); srcRect = dstRect; srcTexture = dstTexture; SkTSwap(dstTexture, tempTexture); } SkIRect srcIRect; srcRect.roundOut(&srcIRect); if (sigmaX > 0.0f) { if (scaleFactorX > 1) { // Clear out a radius to the right of the srcRect to prevent the // X convolution from reading garbage. clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop, radiusX, srcIRect.height()); context->clear(&clearRect, 0x0, false); } context->setRenderTarget(dstTexture->asRenderTarget()); SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); convolve_gaussian(context, srcRect, dstRect, srcTexture, Gr1DKernelEffect::kX_Direction, radiusX, sigmaX, cropToRect); srcTexture = dstTexture; srcRect = dstRect; SkTSwap(dstTexture, tempTexture); } if (sigmaY > 0.0f) { if (scaleFactorY > 1 || sigmaX > 0.0f) { // Clear out a radius below the srcRect to prevent the Y // convolution from reading garbage. clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom, srcIRect.width(), radiusY); context->clear(&clearRect, 0x0, false); } context->setRenderTarget(dstTexture->asRenderTarget()); SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); convolve_gaussian(context, srcRect, dstRect, srcTexture, Gr1DKernelEffect::kY_Direction, radiusY, sigmaY, cropToRect); srcTexture = dstTexture; srcRect = dstRect; SkTSwap(dstTexture, tempTexture); } if (scaleFactorX > 1 || scaleFactorY > 1) { // Clear one pixel to the right and below, to accommodate bilinear // upsampling. clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom, srcIRect.width() + 1, 1); context->clear(&clearRect, 0x0, false); clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop, 1, srcIRect.height()); context->clear(&clearRect, 0x0, false); SkMatrix matrix; matrix.setIDiv(srcTexture->width(), srcTexture->height()); context->setRenderTarget(dstTexture->asRenderTarget()); GrPaint paint; // FIXME: this should be mitchell, not bilinear. GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_FilterMode); paint.addColorTextureEffect(srcTexture, matrix, params); SkRect dstRect(srcRect); scale_rect(&dstRect, (float) scaleFactorX, (float) scaleFactorY); context->drawRectToRect(paint, dstRect, srcRect); srcRect = dstRect; srcTexture = dstTexture; SkTSwap(dstTexture, tempTexture); } if (srcTexture == temp1.texture()) { return temp1.detach(); } else if (srcTexture == temp2.texture()) { return temp2.detach(); } else { srcTexture->ref(); return srcTexture; } }