bool SkImageFilter::filterInputGPU(int index, SkImageFilter::Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { SkImageFilter* input = this->getInput(index); if (!input) { return true; } // Ensure that GrContext calls under filterImage and filterImageGPU below will see an identity // matrix with no clip and that the matrix, clip, and render target set before this function was // called are restored before we return to the caller. GrContext* context = src.getTexture()->getContext(); if (input->filterImage(proxy, src, this->mapContext(ctx), result, offset)) { if (!result->getTexture()) { const SkImageInfo info = result->info(); if (kUnknown_SkColorType == info.colorType()) { return false; } SkAutoTUnref<GrTexture> resultTex( GrRefCachedBitmapTexture(context, *result, GrTextureParams::ClampNoFilter())); if (!resultTex) { return false; } result->setPixelRef(new SkGrPixelRef(info, resultTex))->unref(); } return true; } else { return false; } }
sk_sp<SkSpecialImage> SkSpecialImage::makeTextureImage(GrContext* context) { #if SK_SUPPORT_GPU if (!context) { return nullptr; } if (GrTexture* peek = as_SIB(this)->onPeekTexture()) { return peek->getContext() == context ? sk_sp<SkSpecialImage>(SkRef(this)) : nullptr; } SkBitmap bmp; if (!this->internal_getBM(&bmp)) { return nullptr; } if (bmp.empty()) { return SkSpecialImage::MakeFromRaster(SkIRect::MakeEmpty(), bmp, &this->props()); } SkAutoTUnref<GrTexture> resultTex( GrRefCachedBitmapTexture(context, bmp, GrTextureParams::ClampNoFilter())); if (!resultTex) { return nullptr; } SkAlphaType at = this->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType; return SkSpecialImage::MakeFromGpu(SkIRect::MakeWH(resultTex->width(), resultTex->height()), this->uniqueID(), resultTex, &this->props(), at); #else return nullptr; #endif }
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 }
sk_sp<SkSpecialImage> SkSpecialImage::makeTextureImage(GrContext* context) { #if SK_SUPPORT_GPU if (!context) { return nullptr; } if (GrTexture* peek = as_SIB(this)->onPeekTexture()) { return peek->getContext() == context ? sk_sp<SkSpecialImage>(SkRef(this)) : nullptr; } SkBitmap bmp; // At this point, we are definitely not texture-backed, so we must be raster or generator // backed. If we remove the special-wrapping-an-image subclass, we may be able to assert that // we are strictly raster-backed (i.e. generator images become raster when they are specialized) // in which case getROPixels could turn into peekPixels... if (!this->getROPixels(&bmp)) { return nullptr; } if (bmp.empty()) { return SkSpecialImage::MakeFromRaster(SkIRect::MakeEmpty(), bmp, &this->props()); } sk_sp<GrTexture> resultTex(GrRefCachedBitmapTexture(context, bmp, GrTextureParams::ClampNoFilter(), SkSourceGammaTreatment::kRespect)); if (!resultTex) { return nullptr; } SkAlphaType at = this->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType; return SkSpecialImage::MakeFromGpu(SkIRect::MakeWH(resultTex->width(), resultTex->height()), this->uniqueID(), resultTex, sk_ref_sp(this->getColorSpace()), &this->props(), at); #else return nullptr; #endif }
bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) { #if SK_SUPPORT_GPU SkBitmap input; SkASSERT(fInputCount == 1); if (!SkImageFilterUtils::GetInputResultGPU(this->getInput(0), proxy, src, &input)) { return false; } GrTexture* srcTexture = (GrTexture*) input.getTexture(); SkRect rect; src.getBounds(&rect); GrContext* context = srcTexture->getContext(); GrTextureDesc desc; desc.fFlags = kRenderTarget_GrTextureFlagBit, desc.fWidth = input.width(); desc.fHeight = input.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, rect); GrEffectRef* effect; this->asNewEffect(&effect, srcTexture); SkASSERT(effect); SkAutoUnref effectRef(effect); GrPaint paint; paint.colorStage(0)->setEffect(effect); context->drawRect(paint, rect); SkAutoTUnref<GrTexture> resultTex(dst.detach()); SkImageFilterUtils::WrapTexture(resultTex, input.width(), input.height(), result); return true; #else return false; #endif }
bool SkImageFilter::applyCropRect(const Context& ctx, Proxy* proxy, const SkBitmap& src, SkIPoint* srcOffset, SkIRect* bounds, SkBitmap* dst) const { SkIRect srcBounds; src.getBounds(&srcBounds); srcBounds.offset(*srcOffset); #ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS if (!fCropRect.applyTo(srcBounds, ctx, bounds)) { #else SkIRect dstBounds; this->onFilterNodeBounds(srcBounds, ctx.ctm(), &dstBounds, kForward_MapDirection); if (!fCropRect.applyTo(dstBounds, ctx, bounds)) { #endif return false; } if (srcBounds.contains(*bounds)) { *dst = src; return true; } else { SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds->width(), bounds->height())); if (!device) { return false; } SkCanvas canvas(device); canvas.clear(0x00000000); canvas.drawBitmap(src, srcOffset->x() - bounds->x(), srcOffset->y() - bounds->y()); *srcOffset = SkIPoint::Make(bounds->x(), bounds->y()); *dst = device->accessBitmap(false); return true; } } bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst) const { if (fInputCount < 1) { *dst = src; return true; } SkIRect bounds, totalBounds; this->onFilterNodeBounds(src, ctm, &bounds, kReverse_MapDirection); for (int i = 0; i < fInputCount; ++i) { SkImageFilter* filter = this->getInput(i); SkIRect rect = bounds; if (filter && !filter->filterBounds(bounds, ctm, &rect)) { return false; } if (0 == i) { totalBounds = rect; } else { totalBounds.join(rect); } } // don't modify dst until now, so we don't accidentally change it in the // loop, but then return false on the next filter. *dst = totalBounds; return true; } void SkImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix&, SkIRect* dst, MapDirection) const { *dst = src; } SkImageFilter::Context SkImageFilter::mapContext(const Context& ctx) const { #ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS return ctx; #else SkIRect clipBounds; this->onFilterNodeBounds(ctx.clipBounds(), ctx.ctm(), &clipBounds, MapDirection::kReverse_MapDirection); return Context(ctx.ctm(), clipBounds, ctx.cache()); #endif } bool SkImageFilter::asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&, const SkIRect&) const { return false; } SkImageFilter* SkImageFilter::CreateMatrixFilter(const SkMatrix& matrix, SkFilterQuality filterQuality, SkImageFilter* input) { return SkMatrixImageFilter::Create(matrix, filterQuality, input); } SkImageFilter* SkImageFilter::newWithLocalMatrix(const SkMatrix& matrix) const { // SkLocalMatrixImageFilter takes SkImage* in its factory, but logically that parameter // is *always* treated as a const ptr. Hence the const-cast here. // return SkLocalMatrixImageFilter::Create(matrix, const_cast<SkImageFilter*>(this)); } #if SK_SUPPORT_GPU bool SkImageFilter::filterInputGPU(int index, SkImageFilter::Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { SkImageFilter* input = this->getInput(index); if (!input) { return true; } // Ensure that GrContext calls under filterImage and filterImageGPU below will see an identity // matrix with no clip and that the matrix, clip, and render target set before this function was // called are restored before we return to the caller. GrContext* context = src.getTexture()->getContext(); if (input->filterImage(proxy, src, this->mapContext(ctx), result, offset)) { if (!result->getTexture()) { const SkImageInfo info = result->info(); if (kUnknown_SkColorType == info.colorType()) { return false; } SkAutoTUnref<GrTexture> resultTex( GrRefCachedBitmapTexture(context, *result, GrTextureParams::ClampNoFilter())); if (!resultTex) { return false; } result->setPixelRef(new SkGrPixelRef(info, resultTex))->unref(); } return true; } else { return false; } }