sk_sp<SkSpecialSurface> onMakeSurface(const SkImageInfo& info) const override { #if SK_SUPPORT_GPU GrTexture* texture = as_IB(fImage.get())->peekTexture(); if (texture) { GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(info, *texture->getContext()->caps()); desc.fFlags = kRenderTarget_GrSurfaceFlag; return SkSpecialSurface::MakeRenderTarget(texture->getContext(), desc); } #endif return SkSpecialSurface::MakeRaster(info, nullptr); }
bool SkBlurImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm, SkBitmap* result, SkIPoint* offset) { #if SK_SUPPORT_GPU SkBitmap input; if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, ctm, &input, offset)) { return false; } GrTexture* source = input.getTexture(); SkIRect rect; src.getBounds(&rect); if (!this->applyCropRect(&rect, ctm)) { return false; } SkAutoTUnref<GrTexture> tex(SkGpuBlurUtils::GaussianBlur(source->getContext(), source, false, SkRect::Make(rect), true, fSigma.width(), fSigma.height())); offset->fX += rect.fLeft; offset->fY += rect.fTop; return SkImageFilterUtils::WrapTexture(tex, rect.width(), rect.height(), result); #else SkDEBUGFAIL("Should not call in GPU-less build"); return false; #endif }
GrTexture* GrTextureAdjuster::refTextureSafeForParams(const GrTextureParams& params, SkIPoint* outOffset) { GrTexture* texture = this->originalTexture(); GrContext* context = texture->getContext(); CopyParams copyParams; const SkIRect* contentArea = this->contentAreaOrNull(); if (contentArea && GrTextureParams::kMipMap_FilterMode == params.filterMode()) { // If we generate a MIP chain for texture it will read pixel values from outside the content // area. copyParams.fWidth = contentArea->width(); copyParams.fHeight = contentArea->height(); copyParams.fFilter = GrTextureParams::kBilerp_FilterMode; } else if (!context->getGpu()->makeCopyForTextureParams(texture, params, ©Params)) { if (outOffset) { if (contentArea) { outOffset->set(contentArea->fLeft, contentArea->fRight); } else { outOffset->set(0, 0); } } return SkRef(texture); } GrTexture* copy = this->refCopy(copyParams); if (copy && outOffset) { outOffset->set(0, 0); } return copy; }
bool SkBlurImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { #if SK_SUPPORT_GPU SkBitmap input = src; SkIPoint srcOffset = SkIPoint::Make(0, 0); if (getInput(0) && !getInput(0)->getInputResultGPU(proxy, src, ctx, &input, &srcOffset)) { return false; } SkIRect rect; if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &rect, &input)) { return false; } GrTexture* source = input.getTexture(); SkVector sigma = SkVector::Make(fSigma.width(), fSigma.height()); ctx.ctm().mapVectors(&sigma, 1); sigma.fX = SkMinScalar(sigma.fX, MAX_SIGMA); sigma.fY = SkMinScalar(sigma.fY, MAX_SIGMA); offset->fX = rect.fLeft; offset->fY = rect.fTop; rect.offset(-srcOffset); SkAutoTUnref<GrTexture> tex(SkGpuBlurUtils::GaussianBlur(source->getContext(), source, false, SkRect::Make(rect), true, sigma.x(), sigma.y())); WrapTexture(tex, rect.width(), rect.height(), result); return true; #else SkDEBUGFAIL("Should not call in GPU-less build"); return false; #endif }
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(); GrFragmentProcessor* xferProcessor = NULL; GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag | kNoStencil_GrSurfaceFlag; desc.fWidth = src.width(); desc.fHeight = src.height(); desc.fConfig = kSkia8888_GrPixelConfig; SkAutoTUnref<GrTexture> dst( context->refScratchTexture(desc, GrContext::kApprox_ScratchTexMatch)); if (!dst) { return false; } GrContext::AutoRenderTarget art(context, dst->asRenderTarget()); if (!fMode || !fMode->asFragmentProcessor(&xferProcessor, backgroundTex)) { // canFilterImageGPU() should've taken care of this SkASSERT(false); return false; } SkMatrix foregroundMatrix = GrCoordTransform::MakeDivByTextureWHMatrix(foregroundTex); foregroundMatrix.preTranslate(SkIntToScalar(backgroundOffset.fX-foregroundOffset.fX), SkIntToScalar(backgroundOffset.fY-foregroundOffset.fY)); SkRect srcRect; src.getBounds(&srcRect); GrPaint paint; paint.addColorTextureProcessor(foregroundTex, foregroundMatrix); paint.addColorProcessor(xferProcessor)->unref(); context->drawRect(paint, srcRect); offset->fX = backgroundOffset.fX; offset->fY = backgroundOffset.fY; WrapTexture(dst, src.width(), src.height(), result); return true; }
sk_sp<SkSurface> onMakeTightSurface(const SkImageInfo& info) const override { #if SK_SUPPORT_GPU GrTexture* texture = as_IB(fImage.get())->peekTexture(); if (texture) { return SkSurface::MakeRenderTarget(texture->getContext(), SkBudgeted::kYes, info); } #endif return SkSurface::MakeRaster(info, nullptr); }
DEF_GPUTEST_FOR_NATIVE_CONTEXT(SkImage_newTextureImage, reporter, context, glContext) { GrContextFactory otherFactory; GrContextFactory::ContextInfo otherContextInfo = otherFactory.getContextInfo(GrContextFactory::kNative_GLContextType); glContext->makeCurrent(); std::function<SkImage*()> imageFactories[] = { create_image, create_codec_image, create_data_image, // Create an image from a picture. create_picture_image, // Create a texture image. [context] { return create_gpu_image(context); }, // Create a texture image in a another GrContext. [glContext, otherContextInfo] { otherContextInfo.fGLContext->makeCurrent(); SkImage* otherContextImage = create_gpu_image(otherContextInfo.fGrContext); glContext->makeCurrent(); return otherContextImage; } }; for (auto factory : imageFactories) { SkAutoTUnref<SkImage> image(factory()); if (!image) { ERRORF(reporter, "Error creating image."); continue; } GrTexture* origTexture = as_IB(image)->peekTexture(); SkAutoTUnref<SkImage> texImage(image->newTextureImage(context)); if (!texImage) { // We execpt to fail if image comes from a different GrContext. if (!origTexture || origTexture->getContext() == context) { ERRORF(reporter, "newTextureImage failed."); } continue; } GrTexture* copyTexture = as_IB(texImage)->peekTexture(); if (!copyTexture) { ERRORF(reporter, "newTextureImage returned non-texture image."); continue; } if (origTexture) { if (origTexture != copyTexture) { ERRORF(reporter, "newTextureImage made unnecessary texture copy."); } } if (image->width() != texImage->width() || image->height() != texImage->height()) { ERRORF(reporter, "newTextureImage changed the image size."); } if (image->isOpaque() != texImage->isOpaque()) { ERRORF(reporter, "newTextureImage changed image opaqueness."); } } }
bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { #if SK_SUPPORT_GPU SkBitmap input = src; SkASSERT(fInputCount == 1); SkIPoint srcOffset = SkIPoint::Make(0, 0); if (!this->filterInputGPU(0, proxy, src, ctx, &input, &srcOffset)) { return false; } GrTexture* srcTexture = input.getTexture(); SkIRect bounds; if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) { return false; } SkRect srcRect = SkRect::Make(bounds); SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); GrContext* context = srcTexture->getContext(); GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag, desc.fWidth = bounds.width(); desc.fHeight = bounds.height(); desc.fConfig = kRGBA_8888_GrPixelConfig; SkAutoTUnref<GrTexture> dst(context->textureProvider()->createTexture(desc, GrTextureProvider::FromImageFilter(ctx.sizeConstraint()))); if (!dst) { return false; } // setup new clip GrClip clip(dstRect); GrFragmentProcessor* fp; offset->fX = bounds.left(); offset->fY = bounds.top(); bounds.offset(-srcOffset); SkMatrix matrix(ctx.ctm()); matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); GrPaint paint; if (this->asFragmentProcessor(&fp, srcTexture, matrix, bounds)) { SkASSERT(fp); paint.addColorFragmentProcessor(fp)->unref(); paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget())); if (drawContext) { drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect); WrapTexture(dst, bounds.width(), bounds.height(), result); return true; } } #endif return false; }
GrContext* SkSpecialImage::getContext() const { #if SK_SUPPORT_GPU GrTexture* texture = as_SIB(this)->onPeekTexture(); if (texture) { return texture->getContext(); } #endif return nullptr; }
SkSpecialSurface* onNewSurface(const SkImageInfo& info) const override { #if SK_SUPPORT_GPU GrTexture* texture = as_IB(fImage.get())->peekTexture(); if (texture) { GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(info); desc.fFlags = kRenderTarget_GrSurfaceFlag; return SkSpecialSurface::NewRenderTarget(this->proxy(), texture->getContext(), desc); } #endif return SkSpecialSurface::NewRaster(this->proxy(), info, nullptr); }
SkSurface* SkImage_Gpu::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) const { GrTexture* tex = this->getTexture(); SkASSERT(tex); GrContext* ctx = tex->getContext(); if (!ctx) { // the texture may have been abandoned, so we have to check return NULL; } // TODO: Change signature of onNewSurface to take a budgeted param. const SkSurface::Budgeted budgeted = SkSurface::kNo_Budgeted; return SkSurface::NewRenderTarget(ctx, budgeted, info, fSampleCountForNewSurfaces, &props); }
GrBackendObject SkImage::getTextureHandle(bool flushPendingGrContextIO) const { GrTexture* texture = as_IB(this)->getTexture(); if (texture) { GrContext* context = texture->getContext(); if (context) { if (flushPendingGrContextIO) { context->prepareSurfaceForExternalIO(texture); } } return texture->getTextureHandle(); } return 0; }
bool SkBlurImageFilter::filterImageGPUDeprecated(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { #if SK_SUPPORT_GPU SkBitmap input = src; SkIPoint srcOffset = SkIPoint::Make(0, 0); if (!this->filterInputGPUDeprecated(0, proxy, src, ctx, &input, &srcOffset)) { return false; } SkIRect srcBounds = input.bounds(); srcBounds.offset(srcOffset); SkIRect dstBounds; if (!this->applyCropRect(this->mapContext(ctx), srcBounds, &dstBounds)) { return false; } if (!srcBounds.intersect(dstBounds)) { return false; } SkVector sigma = map_sigma(fSigma, ctx.ctm()); if (sigma.x() == 0 && sigma.y() == 0) { input.extractSubset(result, srcBounds); offset->fX = srcBounds.x(); offset->fY = srcBounds.y(); return true; } offset->fX = dstBounds.fLeft; offset->fY = dstBounds.fTop; srcBounds.offset(-srcOffset); dstBounds.offset(-srcOffset); SkRect srcBoundsF(SkRect::Make(srcBounds)); GrTexture* inputTexture = input.getTexture(); SkAutoTUnref<GrTexture> tex(SkGpuBlurUtils::GaussianBlur(inputTexture->getContext(), inputTexture, false, SkRect::Make(dstBounds), &srcBoundsF, sigma.x(), sigma.y())); if (!tex) { return false; } GrWrapTextureInBitmap(tex, dstBounds.width(), dstBounds.height(), false, result); return true; #else SkDEBUGFAIL("Should not call in GPU-less build"); return false; #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 }
bool SkBlurImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { #if SK_SUPPORT_GPU SkBitmap input = src; SkIPoint srcOffset = SkIPoint::Make(0, 0); if (!this->filterInputGPU(0, proxy, src, ctx, &input, &srcOffset)) { return false; } SkIRect srcBounds, dstBounds; if (!this->applyCropRect(this->mapContext(ctx), input, srcOffset, &dstBounds, &srcBounds)) { return false; } if (!srcBounds.intersect(dstBounds)) { return false; } GrTexture* source = input.getTexture(); SkVector sigma = mapSigma(fSigma, ctx.ctm()); offset->fX = dstBounds.fLeft; offset->fY = dstBounds.fTop; srcBounds.offset(-srcOffset); dstBounds.offset(-srcOffset); SkRect srcBoundsF(SkRect::Make(srcBounds)); auto constraint = GrTextureProvider::FromImageFilter(ctx.sizeConstraint()); SkAutoTUnref<GrTexture> tex(SkGpuBlurUtils::GaussianBlur(source->getContext(), source, false, SkRect::Make(dstBounds), &srcBoundsF, sigma.x(), sigma.y(), constraint)); if (!tex) { return false; } WrapTexture(tex, dstBounds.width(), dstBounds.height(), result); return true; #else SkDEBUGFAIL("Should not call in GPU-less build"); return false; #endif }
GrTexture* GrTextureAdjuster::refCopy(const CopyParams& copyParams) { GrTexture* texture = this->originalTexture(); GrContext* context = texture->getContext(); const SkIRect* contentArea = this->contentAreaOrNull(); GrUniqueKey key; this->makeCopyKey(copyParams, &key); if (key.isValid()) { GrTexture* cachedCopy = context->textureProvider()->findAndRefTextureByUniqueKey(key); if (cachedCopy) { return cachedCopy; } } GrTexture* copy = copy_on_gpu(texture, contentArea, copyParams); if (copy) { if (key.isValid()) { copy->resourcePriv().setUniqueKey(key); this->didCacheCopy(key); } } return copy; }
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 SkXfermodeImageFilter::filterImageGPUDeprecated(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { GrContext* context = nullptr; SkBitmap background = src; SkIPoint backgroundOffset = SkIPoint::Make(0, 0); if (!this->filterInputGPUDeprecated(0, proxy, src, ctx, &background, &backgroundOffset)) { background.reset(); } GrTexture* backgroundTex = background.getTexture(); if (backgroundTex) { context = backgroundTex->getContext(); } SkBitmap foreground = src; SkIPoint foregroundOffset = SkIPoint::Make(0, 0); if (!this->filterInputGPUDeprecated(1, proxy, src, ctx, &foreground, &foregroundOffset)) { foreground.reset(); } GrTexture* foregroundTex = foreground.getTexture(); if (foregroundTex) { context = foregroundTex->getContext(); } if (!context) { return false; } SkIRect bounds = background.bounds().makeOffset(backgroundOffset.x(), backgroundOffset.y()); bounds.join(foreground.bounds().makeOffset(foregroundOffset.x(), foregroundOffset.y())); if (bounds.isEmpty()) { return false; } GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fWidth = bounds.width(); desc.fHeight = bounds.height(); desc.fConfig = kSkia8888_GrPixelConfig; SkAutoTUnref<GrTexture> dst(context->textureProvider()->createApproxTexture(desc)); if (!dst) { return false; } GrPaint paint; SkAutoTUnref<const GrFragmentProcessor> bgFP; if (backgroundTex) { SkMatrix backgroundMatrix; backgroundMatrix.setIDiv(backgroundTex->width(), backgroundTex->height()); backgroundMatrix.preTranslate(SkIntToScalar(-backgroundOffset.fX), SkIntToScalar(-backgroundOffset.fY)); bgFP.reset(GrTextureDomainEffect::Create( backgroundTex, backgroundMatrix, GrTextureDomain::MakeTexelDomain(backgroundTex, background.bounds()), GrTextureDomain::kDecal_Mode, GrTextureParams::kNone_FilterMode)); } else { bgFP.reset(GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK, GrConstColorProcessor::kIgnore_InputMode)); } if (foregroundTex) { SkMatrix foregroundMatrix; foregroundMatrix.setIDiv(foregroundTex->width(), foregroundTex->height()); foregroundMatrix.preTranslate(SkIntToScalar(-foregroundOffset.fX), SkIntToScalar(-foregroundOffset.fY)); SkAutoTUnref<const GrFragmentProcessor> foregroundFP; foregroundFP.reset(GrTextureDomainEffect::Create( foregroundTex, foregroundMatrix, GrTextureDomain::MakeTexelDomain(foregroundTex, foreground.bounds()), GrTextureDomain::kDecal_Mode, GrTextureParams::kNone_FilterMode)); paint.addColorFragmentProcessor(foregroundFP.get()); // A null fMode is interpreted to mean kSrcOver_Mode (to match raster). SkAutoTUnref<SkXfermode> mode(SkSafeRef(fMode.get())); if (!mode) { // It would be awesome to use SkXfermode::Create here but it knows better // than us and won't return a kSrcOver_Mode SkXfermode. That means we // have to get one the hard way. struct ProcCoeff rec; rec.fProc = SkXfermode::GetProc(SkXfermode::kSrcOver_Mode); SkXfermode::ModeAsCoeff(SkXfermode::kSrcOver_Mode, &rec.fSC, &rec.fDC); mode.reset(new SkProcCoeffXfermode(rec, SkXfermode::kSrcOver_Mode)); } SkAutoTUnref<const GrFragmentProcessor> xferFP(mode->getFragmentProcessorForImageFilter(bgFP)); // A null 'xferFP' here means kSrc_Mode was used in which case we can just proceed if (xferFP) { paint.addColorFragmentProcessor(xferFP); } } else { paint.addColorFragmentProcessor(bgFP); } paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget())); if (!drawContext) { return false; } SkMatrix matrix; matrix.setTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); drawContext->drawRect(GrClip::WideOpen(), paint, matrix, SkRect::Make(bounds)); offset->fX = bounds.left(); offset->fY = bounds.top(); GrWrapTextureInBitmap(dst, bounds.width(), bounds.height(), false, result); return true; }
bool SkDisplacementMapEffect::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { SkBitmap colorBM = src; SkIPoint colorOffset = SkIPoint::Make(0, 0); if (getColorInput() && !getColorInput()->getInputResultGPU(proxy, src, ctx, &colorBM, &colorOffset)) { return false; } SkBitmap displacementBM = src; SkIPoint displacementOffset = SkIPoint::Make(0, 0); if (getDisplacementInput() && !getDisplacementInput()->getInputResultGPU(proxy, src, ctx, &displacementBM, &displacementOffset)) { return false; } SkIRect bounds; // Since GrDisplacementMapEffect does bounds checking on color pixel access, we don't need to // pad the color bitmap to bounds here. if (!this->applyCropRect(ctx, colorBM, colorOffset, &bounds)) { return false; } SkIRect displBounds; if (!this->applyCropRect(ctx, proxy, displacementBM, &displacementOffset, &displBounds, &displacementBM)) { return false; } if (!bounds.intersect(displBounds)) { return false; } GrTexture* color = colorBM.getTexture(); GrTexture* displacement = displacementBM.getTexture(); GrContext* context = color->getContext(); GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fWidth = bounds.width(); desc.fHeight = bounds.height(); desc.fConfig = kSkia8888_GrPixelConfig; SkAutoTUnref<GrTexture> dst( context->refScratchTexture(desc, GrContext::kApprox_ScratchTexMatch)); if (!dst) { return false; } SkVector scale = SkVector::Make(fScale, fScale); ctx.ctm().mapVectors(&scale, 1); GrPaint paint; SkMatrix offsetMatrix = GrCoordTransform::MakeDivByTextureWHMatrix(displacement); offsetMatrix.preTranslate(SkIntToScalar(colorOffset.fX - displacementOffset.fX), SkIntToScalar(colorOffset.fY - displacementOffset.fY)); paint.addColorProcessor( GrDisplacementMapEffect::Create(fXChannelSelector, fYChannelSelector, scale, displacement, offsetMatrix, color, colorBM.dimensions()))->unref(); SkIRect colorBounds = bounds; colorBounds.offset(-colorOffset); SkMatrix matrix; matrix.setTranslate(-SkIntToScalar(colorBounds.x()), -SkIntToScalar(colorBounds.y())); context->drawRect(dst->asRenderTarget(), GrClip::WideOpen(), paint, matrix, SkRect::Make(colorBounds)); offset->fX = bounds.left(); offset->fY = bounds.top(); WrapTexture(dst, bounds.width(), bounds.height(), result); return true; }
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 (this->getInput(0) && !this->getInput(0)->getInputResultGPU(proxy, src, ctx, &background, &backgroundOffset)) { return this->onFilterImage(proxy, src, ctx, result, offset); } GrTexture* backgroundTex = background.getTexture(); if (NULL == backgroundTex) { SkASSERT(false); return false; } SkBitmap foreground = src; SkIPoint foregroundOffset = SkIPoint::Make(0, 0); if (this->getInput(1) && !this->getInput(1)->getInputResultGPU(proxy, src, ctx, &foreground, &foregroundOffset)) { return this->onFilterImage(proxy, src, ctx, result, offset); } GrTexture* foregroundTex = foreground.getTexture(); GrContext* context = foregroundTex->getContext(); GrFragmentProcessor* xferProcessor = NULL; GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fWidth = src.width(); desc.fHeight = src.height(); desc.fConfig = kSkia8888_GrPixelConfig; SkAutoTUnref<GrTexture> dst(context->textureProvider()->refScratchTexture( desc, GrTextureProvider::kApprox_ScratchTexMatch)); if (!dst) { return false; } GrPaint paint; if (!fMode || !fMode->asFragmentProcessor(&xferProcessor, paint.getProcessorDataManager(), backgroundTex)) { // canFilterImageGPU() should've taken care of this SkASSERT(false); return false; } SkMatrix foregroundMatrix = GrCoordTransform::MakeDivByTextureWHMatrix(foregroundTex); foregroundMatrix.preTranslate(SkIntToScalar(backgroundOffset.fX-foregroundOffset.fX), SkIntToScalar(backgroundOffset.fY-foregroundOffset.fY)); SkRect srcRect; src.getBounds(&srcRect); SkAutoTUnref<GrFragmentProcessor> foregroundDomain(GrTextureDomainEffect::Create( paint.getProcessorDataManager(), foregroundTex, foregroundMatrix, GrTextureDomain::MakeTexelDomain(foregroundTex, foreground.bounds()), GrTextureDomain::kDecal_Mode, GrTextureParams::kNone_FilterMode) ); paint.addColorProcessor(foregroundDomain.get()); paint.addColorProcessor(xferProcessor)->unref(); GrDrawContext* drawContext = context->drawContext(); if (!drawContext) { return false; } drawContext->drawRect(dst->asRenderTarget(), GrClip::WideOpen(), paint, SkMatrix::I(), srcRect); offset->fX = backgroundOffset.fX; offset->fY = backgroundOffset.fY; WrapTexture(dst, src.width(), src.height(), result); return true; }
sk_sp<SkSpecialImage> SkBlurImageFilter::onFilterImage(SkSpecialImage* source, const Context& ctx, SkIPoint* offset) const { SkIPoint inputOffset = SkIPoint::Make(0, 0); sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset)); if (!input) { return nullptr; } SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.fX, inputOffset.fY, input->width(), input->height()); SkIRect dstBounds; if (!this->applyCropRect(this->mapContext(ctx), inputBounds, &dstBounds)) { return nullptr; } if (!inputBounds.intersect(dstBounds)) { return nullptr; } const SkVector sigma = map_sigma(fSigma, ctx.ctm()); #if SK_SUPPORT_GPU if (input->peekTexture() && input->peekTexture()->getContext()) { if (0 == sigma.x() && 0 == sigma.y()) { offset->fX = inputBounds.x(); offset->fY = inputBounds.y(); return input->makeSubset(inputBounds.makeOffset(-inputOffset.x(), -inputOffset.y())); } GrTexture* inputTexture = input->peekTexture(); offset->fX = dstBounds.fLeft; offset->fY = dstBounds.fTop; inputBounds.offset(-inputOffset); dstBounds.offset(-inputOffset); SkRect inputBoundsF(SkRect::Make(inputBounds)); SkAutoTUnref<GrTexture> tex(SkGpuBlurUtils::GaussianBlur(inputTexture->getContext(), inputTexture, false, source->props().allowSRGBInputs(), SkRect::Make(dstBounds), &inputBoundsF, sigma.x(), sigma.y())); if (!tex) { return nullptr; } return SkSpecialImage::MakeFromGpu(source->internal_getProxy(), SkIRect::MakeWH(dstBounds.width(), dstBounds.height()), kNeedNewImageUniqueID_SpecialImage, tex, &source->props()); } #endif int kernelSizeX, kernelSizeX3, lowOffsetX, highOffsetX; int kernelSizeY, kernelSizeY3, lowOffsetY, highOffsetY; get_box3_params(sigma.x(), &kernelSizeX, &kernelSizeX3, &lowOffsetX, &highOffsetX); get_box3_params(sigma.y(), &kernelSizeY, &kernelSizeY3, &lowOffsetY, &highOffsetY); if (kernelSizeX < 0 || kernelSizeY < 0) { return nullptr; } if (kernelSizeX == 0 && kernelSizeY == 0) { offset->fX = inputBounds.x(); offset->fY = inputBounds.y(); return input->makeSubset(inputBounds.makeOffset(-inputOffset.x(), -inputOffset.y())); } SkPixmap inputPixmap; if (!input->peekPixels(&inputPixmap)) { return nullptr; } if (inputPixmap.colorType() != kN32_SkColorType) { return nullptr; } SkImageInfo info = SkImageInfo::Make(dstBounds.width(), dstBounds.height(), inputPixmap.colorType(), inputPixmap.alphaType()); SkBitmap tmp, dst; if (!tmp.tryAllocPixels(info) || !dst.tryAllocPixels(info)) { return nullptr; } SkAutoLockPixels tmpLock(tmp), dstLock(dst); offset->fX = dstBounds.fLeft; offset->fY = dstBounds.fTop; SkPMColor* t = tmp.getAddr32(0, 0); SkPMColor* d = dst.getAddr32(0, 0); int w = dstBounds.width(), h = dstBounds.height(); const SkPMColor* s = inputPixmap.addr32(inputBounds.x() - inputOffset.x(), inputBounds.y() - inputOffset.y()); inputBounds.offset(-dstBounds.x(), -dstBounds.y()); dstBounds.offset(-dstBounds.x(), -dstBounds.y()); SkIRect inputBoundsT = SkIRect::MakeLTRB(inputBounds.top(), inputBounds.left(), inputBounds.bottom(), inputBounds.right()); SkIRect dstBoundsT = SkIRect::MakeWH(dstBounds.height(), dstBounds.width()); int sw = int(inputPixmap.rowBytes() >> 2); /** * * In order to make memory accesses cache-friendly, we reorder the passes to * use contiguous memory reads wherever possible. * * For example, the 6 passes of the X-and-Y blur case are rewritten as * follows. Instead of 3 passes in X and 3 passes in Y, we perform * 2 passes in X, 1 pass in X transposed to Y on write, 2 passes in X, * then 1 pass in X transposed to Y on write. * * +----+ +----+ +----+ +---+ +---+ +---+ +----+ * + AB + ----> | AB | ----> | AB | -----> | A | ----> | A | ----> | A | -----> | AB | * +----+ blurX +----+ blurX +----+ blurXY | B | blurX | B | blurX | B | blurXY +----+ * +---+ +---+ +---+ * * In this way, two of the y-blurs become x-blurs applied to transposed * images, and all memory reads are contiguous. */ if (kernelSizeX > 0 && kernelSizeY > 0) { SkOpts::box_blur_xx(s, sw, inputBounds, t, kernelSizeX, lowOffsetX, highOffsetX, w, h); SkOpts::box_blur_xx(t, w, dstBounds, d, kernelSizeX, highOffsetX, lowOffsetX, w, h); SkOpts::box_blur_xy(d, w, dstBounds, t, kernelSizeX3, highOffsetX, highOffsetX, w, h); SkOpts::box_blur_xx(t, h, dstBoundsT, d, kernelSizeY, lowOffsetY, highOffsetY, h, w); SkOpts::box_blur_xx(d, h, dstBoundsT, t, kernelSizeY, highOffsetY, lowOffsetY, h, w); SkOpts::box_blur_xy(t, h, dstBoundsT, d, kernelSizeY3, highOffsetY, highOffsetY, h, w); } else if (kernelSizeX > 0) { SkOpts::box_blur_xx(s, sw, inputBounds, d, kernelSizeX, lowOffsetX, highOffsetX, w, h); SkOpts::box_blur_xx(d, w, dstBounds, t, kernelSizeX, highOffsetX, lowOffsetX, w, h); SkOpts::box_blur_xx(t, w, dstBounds, d, kernelSizeX3, highOffsetX, highOffsetX, w, h); } else if (kernelSizeY > 0) { SkOpts::box_blur_yx(s, sw, inputBoundsT, d, kernelSizeY, lowOffsetY, highOffsetY, h, w); SkOpts::box_blur_xx(d, h, dstBoundsT, t, kernelSizeY, highOffsetY, lowOffsetY, h, w); SkOpts::box_blur_xy(t, h, dstBoundsT, d, kernelSizeY3, highOffsetY, highOffsetY, h, w); } return SkSpecialImage::MakeFromRaster(source->internal_getProxy(), SkIRect::MakeWH(dstBounds.width(), dstBounds.height()), dst, &source->props()); }
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); }
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 (!this->filterInputGPU(0, proxy, src, ctx, &background, &backgroundOffset)) { return false; } GrTexture* backgroundTex = background.getTexture(); if (nullptr == backgroundTex) { SkASSERT(false); return false; } SkBitmap foreground = src; SkIPoint foregroundOffset = SkIPoint::Make(0, 0); if (!this->filterInputGPU(1, proxy, src, ctx, &foreground, &foregroundOffset)) { return false; } GrTexture* foregroundTex = foreground.getTexture(); GrContext* context = foregroundTex->getContext(); SkIRect bounds = background.bounds().makeOffset(backgroundOffset.x(), backgroundOffset.y()); bounds.join(foreground.bounds().makeOffset(foregroundOffset.x(), foregroundOffset.y())); if (bounds.isEmpty()) { return false; } const GrFragmentProcessor* xferFP = nullptr; GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fWidth = bounds.width(); desc.fHeight = bounds.height(); desc.fConfig = kSkia8888_GrPixelConfig; SkAutoTUnref<GrTexture> dst(context->textureProvider()->createApproxTexture(desc)); if (!dst) { return false; } GrPaint paint; SkMatrix backgroundMatrix; backgroundMatrix.setIDiv(backgroundTex->width(), backgroundTex->height()); backgroundMatrix.preTranslate(SkIntToScalar(-backgroundOffset.fX), SkIntToScalar(-backgroundOffset.fY)); SkAutoTUnref<const GrFragmentProcessor> bgFP(GrTextureDomainEffect::Create( backgroundTex, backgroundMatrix, GrTextureDomain::MakeTexelDomain(backgroundTex, background.bounds()), GrTextureDomain::kDecal_Mode, GrTextureParams::kNone_FilterMode) ); if (!fMode || !fMode->asFragmentProcessor(&xferFP, bgFP)) { // canFilterImageGPU() should've taken care of this SkASSERT(false); return false; } SkMatrix foregroundMatrix; foregroundMatrix.setIDiv(foregroundTex->width(), foregroundTex->height()); foregroundMatrix.preTranslate(SkIntToScalar(-foregroundOffset.fX), SkIntToScalar(-foregroundOffset.fY)); SkAutoTUnref<const GrFragmentProcessor> foregroundFP(GrTextureDomainEffect::Create( foregroundTex, foregroundMatrix, GrTextureDomain::MakeTexelDomain(foregroundTex, foreground.bounds()), GrTextureDomain::kDecal_Mode, GrTextureParams::kNone_FilterMode) ); paint.addColorFragmentProcessor(foregroundFP.get()); if (xferFP) { paint.addColorFragmentProcessor(xferFP)->unref(); } paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget())); if (!drawContext) { return false; } SkMatrix matrix; matrix.setTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); drawContext->drawRect(GrClip::WideOpen(), paint, matrix, SkRect::Make(bounds)); offset->fX = bounds.left(); offset->fY = bounds.top(); GrWrapTextureInBitmap(dst, bounds.width(), bounds.height(), false, result); return true; }