From 0ea330703e723bdf3038742d594dd13e2f33c770 Mon Sep 17 00:00:00 2001 From: Brian Salomon Date: Tue, 14 Jul 2020 10:43:42 -0400 Subject: [PATCH] Make GrTextureProducer take optional subset and domain rects Split bicubic into separate functions. Removes usage of null GrSamplerState::Filter to indicate bicubic. Bug: skia:10344 Change-Id: Ife649ba84afe3a06d7d8fb0d46677ce96fc264dc Reviewed-on: https://skia-review.googlesource.com/c/skia/+/302636 Reviewed-by: Michael Ludwig Commit-Queue: Brian Salomon --- src/gpu/GrImageTextureMaker.cpp | 64 ++++++++++----------- src/gpu/GrImageTextureMaker.h | 15 +++-- src/gpu/GrTextureAdjuster.cpp | 40 +++++-------- src/gpu/GrTextureAdjuster.h | 15 +++-- src/gpu/GrTextureMaker.cpp | 38 +++++------- src/gpu/GrTextureMaker.h | 15 +++-- src/gpu/GrTextureProducer.cpp | 86 ++++++++++++++++------------ src/gpu/GrTextureProducer.h | 78 +++++++++++++++---------- src/gpu/SkGpuDevice_drawTexture.cpp | 25 ++++---- src/gpu/effects/GrTextureEffect.cpp | 3 +- src/gpu/effects/GrTextureEffect.h | 4 +- src/gpu/effects/GrYUVtoRGBEffect.cpp | 45 ++++++++++++--- src/gpu/effects/GrYUVtoRGBEffect.h | 3 +- src/shaders/SkImageShader.cpp | 16 +++--- 14 files changed, 249 insertions(+), 198 deletions(-) diff --git a/src/gpu/GrImageTextureMaker.cpp b/src/gpu/GrImageTextureMaker.cpp index 581f28570e..4d47c20124 100644 --- a/src/gpu/GrImageTextureMaker.cpp +++ b/src/gpu/GrImageTextureMaker.cpp @@ -60,50 +60,48 @@ GrSurfaceProxyView GrYUVAImageTextureMaker::refOriginalTextureProxyView(GrMipMap std::unique_ptr GrYUVAImageTextureMaker::createFragmentProcessor( const SkMatrix& textureMatrix, - const SkRect& constraintRect, - FilterConstraint filterConstraint, - bool coordsLimitedToConstraintRect, - GrSamplerState::WrapMode wrapX, - GrSamplerState::WrapMode wrapY, - const GrSamplerState::Filter* filterOrNullForBicubic) { + const SkRect* subset, + const SkRect* domain, + GrSamplerState samplerState) { // Check whether it's already been flattened. if (fImage->fRGBView.proxy()) { - return this->INHERITED::createFragmentProcessor( - textureMatrix, constraintRect, filterConstraint, coordsLimitedToConstraintRect, - wrapX, wrapY, filterOrNullForBicubic); + return this->INHERITED::createFragmentProcessor(textureMatrix, subset, domain, + samplerState); } - GrSamplerState::Filter filter = - filterOrNullForBicubic ? *filterOrNullForBicubic : GrSamplerState::Filter::kNearest; - // Check to see if the client has given us pre-mipped textures or we can generate them // If not, fall back to bilerp. Also fall back to bilerp when a domain is requested - if (GrSamplerState::Filter::kMipMap == filter && - (filterConstraint == GrTextureProducer::kYes_FilterConstraint || - !fImage->setupMipmapsForPlanes(this->context()))) { - filter = GrSamplerState::Filter::kBilerp; - } - - // Cannot rely on GrTextureProducer's domain infrastructure since we need to calculate domain's - // per plane, which may be different, so respect the filterConstraint without any additional - // analysis. - const SkRect* domain = nullptr; - if (filterConstraint == GrTextureProducer::kYes_FilterConstraint) { - domain = &constraintRect; + if (samplerState.filter() == GrSamplerState::Filter::kMipMap && + (subset || !fImage->setupMipmapsForPlanes(this->context()))) { + samplerState.setFilterMode(GrSamplerState::Filter::kBilerp); } const auto& caps = *fImage->context()->priv().caps(); - const SkMatrix& m = filterOrNullForBicubic ? textureMatrix : SkMatrix::I(); - GrSamplerState sampler(wrapX, wrapY, filter); auto fp = GrYUVtoRGBEffect::Make(fImage->fViews, fImage->fYUVAIndices, fImage->fYUVColorSpace, - sampler, caps, m, domain); - if (!filterOrNullForBicubic) { - fp = GrBicubicEffect::Make(std::move(fp), - fImage->alphaType(), - textureMatrix, - GrBicubicEffect::Kernel::kMitchell, - GrBicubicEffect::Direction::kXY); + samplerState, caps, textureMatrix, subset, domain); + if (fImage->fFromColorSpace) { + fp = GrColorSpaceXformEffect::Make(std::move(fp), fImage->fFromColorSpace.get(), + fImage->alphaType(), fImage->colorSpace(), + kPremul_SkAlphaType); } + return fp; +} + +std::unique_ptr GrYUVAImageTextureMaker::createBicubicFragmentProcessor( + const SkMatrix& textureMatrix, + const SkRect* subset, + const SkRect* domain, + GrSamplerState::WrapMode wrapX, + GrSamplerState::WrapMode wrapY) { + const auto& caps = *fImage->context()->priv().caps(); + GrSamplerState samplerState(wrapX, wrapY, GrSamplerState::Filter::kNearest); + auto fp = GrYUVtoRGBEffect::Make(fImage->fViews, fImage->fYUVAIndices, fImage->fYUVColorSpace, + samplerState, caps, SkMatrix::I(), subset, domain); + fp = GrBicubicEffect::Make(std::move(fp), + fImage->alphaType(), + textureMatrix, + GrBicubicEffect::Kernel::kMitchell, + GrBicubicEffect::Direction::kXY); if (fImage->fFromColorSpace) { fp = GrColorSpaceXformEffect::Make(std::move(fp), fImage->fFromColorSpace.get(), fImage->alphaType(), diff --git a/src/gpu/GrImageTextureMaker.h b/src/gpu/GrImageTextureMaker.h index 8636b8ac65..2d565eddf3 100644 --- a/src/gpu/GrImageTextureMaker.h +++ b/src/gpu/GrImageTextureMaker.h @@ -35,14 +35,17 @@ class GrYUVAImageTextureMaker final : public GrTextureMaker { public: GrYUVAImageTextureMaker(GrRecordingContext* context, const SkImage* client); - std::unique_ptr createFragmentProcessor( + std::unique_ptr createFragmentProcessor(const SkMatrix& textureMatrix, + const SkRect* subset, + const SkRect* domain, + GrSamplerState) override; + + std::unique_ptr createBicubicFragmentProcessor( const SkMatrix& textureMatrix, - const SkRect& constraintRect, - FilterConstraint filterConstraint, - bool coordsLimitedToConstraintRect, + const SkRect* subset, + const SkRect* domain, GrSamplerState::WrapMode wrapX, - GrSamplerState::WrapMode wrapY, - const GrSamplerState::Filter* filterOrNullForBicubic) override; + GrSamplerState::WrapMode wrapY) override; bool isPlanar() const override { return true; } diff --git a/src/gpu/GrTextureAdjuster.cpp b/src/gpu/GrTextureAdjuster.cpp index 59e7cd882c..6f3cd879dd 100644 --- a/src/gpu/GrTextureAdjuster.cpp +++ b/src/gpu/GrTextureAdjuster.cpp @@ -77,29 +77,19 @@ GrSurfaceProxyView GrTextureAdjuster::onView(GrMipMapped mipMapped) { std::unique_ptr GrTextureAdjuster::createFragmentProcessor( const SkMatrix& textureMatrix, - const SkRect& constraintRect, - FilterConstraint filterConstraint, - bool coordsLimitedToConstraintRect, - GrSamplerState::WrapMode wrapX, - GrSamplerState::WrapMode wrapY, - const GrSamplerState::Filter* filterOrNullForBicubic) { - GrSurfaceProxyView view; - if (filterOrNullForBicubic) { - view = this->view(*filterOrNullForBicubic); - } else { - view = this->view(GrMipMapped::kNo); - } - if (!view) { - return nullptr; - } - SkASSERT(view.asTextureProxy()); - - return this->createFragmentProcessorForSubsetAndFilter(std::move(view), - textureMatrix, - coordsLimitedToConstraintRect, - filterConstraint, - constraintRect, - wrapX, - wrapY, - filterOrNullForBicubic); + const SkRect* subset, + const SkRect* domain, + GrSamplerState samplerState) { + return this->createFragmentProcessorForView( + this->view(samplerState.filter()), textureMatrix, subset, domain, samplerState); +} + +std::unique_ptr GrTextureAdjuster::createBicubicFragmentProcessor( + const SkMatrix& textureMatrix, + const SkRect* subset, + const SkRect* domain, + GrSamplerState::WrapMode wrapX, + GrSamplerState::WrapMode wrapY) { + return this->createBicubicFragmentProcessorForView( + this->view(GrMipMapped::kNo), textureMatrix, subset, domain, wrapX, wrapY); } diff --git a/src/gpu/GrTextureAdjuster.h b/src/gpu/GrTextureAdjuster.h index d9ce1f0441..0494b21907 100644 --- a/src/gpu/GrTextureAdjuster.h +++ b/src/gpu/GrTextureAdjuster.h @@ -23,14 +23,17 @@ public: GrTextureAdjuster(GrRecordingContext*, GrSurfaceProxyView, const GrColorInfo&, uint32_t uniqueID); - std::unique_ptr createFragmentProcessor( + std::unique_ptr createFragmentProcessor(const SkMatrix& textureMatrix, + const SkRect* subset, + const SkRect* domain, + GrSamplerState) override; + + std::unique_ptr createBicubicFragmentProcessor( const SkMatrix& textureMatrix, - const SkRect& constraintRect, - FilterConstraint, - bool coordsLimitedToConstraintRect, + const SkRect* subset, + const SkRect* domain, GrSamplerState::WrapMode wrapX, - GrSamplerState::WrapMode wrapY, - const GrSamplerState::Filter* filterOrNullForBicubic) override; + GrSamplerState::WrapMode wrapY) override; private: GrSurfaceProxyView onView(GrMipMapped) override; diff --git a/src/gpu/GrTextureMaker.cpp b/src/gpu/GrTextureMaker.cpp index bddf275118..f02365e9c6 100644 --- a/src/gpu/GrTextureMaker.cpp +++ b/src/gpu/GrTextureMaker.cpp @@ -24,28 +24,20 @@ GrSurfaceProxyView GrTextureMaker::onView(GrMipMapped mipMapped) { std::unique_ptr GrTextureMaker::createFragmentProcessor( const SkMatrix& textureMatrix, - const SkRect& constraintRect, - FilterConstraint filterConstraint, - bool coordsLimitedToConstraintRect, - GrSamplerState::WrapMode wrapX, - GrSamplerState::WrapMode wrapY, - const GrSamplerState::Filter* filterOrNullForBicubic) { + const SkRect* subset, + const SkRect* domain, + GrSamplerState sampler) { GrSurfaceProxyView view; - if (filterOrNullForBicubic) { - view = this->view(*filterOrNullForBicubic); - } else { - view = this->view(GrMipMapped::kNo); - } - if (!view) { - return nullptr; - } - - return this->createFragmentProcessorForSubsetAndFilter(std::move(view), - textureMatrix, - coordsLimitedToConstraintRect, - filterConstraint, - constraintRect, - wrapX, - wrapY, - filterOrNullForBicubic); + return this->createFragmentProcessorForView( + this->view(sampler.filter()), textureMatrix, subset, domain, sampler); +} + +std::unique_ptr GrTextureMaker::createBicubicFragmentProcessor( + const SkMatrix& textureMatrix, + const SkRect* subset, + const SkRect* domain, + GrSamplerState::WrapMode wrapX, + GrSamplerState::WrapMode wrapY) { + return this->createBicubicFragmentProcessorForView( + this->view(GrMipMapped::kNo), textureMatrix, subset, domain, wrapX, wrapY); } diff --git a/src/gpu/GrTextureMaker.h b/src/gpu/GrTextureMaker.h index 73a904201e..4ce4cdf731 100644 --- a/src/gpu/GrTextureMaker.h +++ b/src/gpu/GrTextureMaker.h @@ -16,14 +16,17 @@ */ class GrTextureMaker : public GrTextureProducer { public: - std::unique_ptr createFragmentProcessor( + std::unique_ptr createFragmentProcessor(const SkMatrix& textureMatrix, + const SkRect* subset, + const SkRect* domain, + GrSamplerState) override; + + std::unique_ptr createBicubicFragmentProcessor( const SkMatrix& textureMatrix, - const SkRect& constraintRect, - FilterConstraint filterConstraint, - bool coordsLimitedToConstraintRect, + const SkRect* subset, + const SkRect* domain, GrSamplerState::WrapMode wrapX, - GrSamplerState::WrapMode wrapY, - const GrSamplerState::Filter* filterOrNullForBicubic) override; + GrSamplerState::WrapMode wrapY) override; protected: GrTextureMaker(GrRecordingContext* context, const GrImageInfo& info) diff --git a/src/gpu/GrTextureProducer.cpp b/src/gpu/GrTextureProducer.cpp index 2a1d6d6cb0..95564970a9 100644 --- a/src/gpu/GrTextureProducer.cpp +++ b/src/gpu/GrTextureProducer.cpp @@ -20,58 +20,68 @@ #include "src/gpu/effects/GrBicubicEffect.h" #include "src/gpu/effects/GrTextureEffect.h" -std::unique_ptr GrTextureProducer::createFragmentProcessorForSubsetAndFilter( +std::unique_ptr GrTextureProducer::createFragmentProcessorForView( GrSurfaceProxyView view, const SkMatrix& textureMatrix, - bool coordsLimitedToConstraintRect, - FilterConstraint filterConstraint, - const SkRect& constraintRect, - GrSamplerState::WrapMode wrapX, - GrSamplerState::WrapMode wrapY, - const GrSamplerState::Filter* filterOrNullForBicubic) { + const SkRect* subset, + const SkRect* domain, + GrSamplerState samplerState) { + if (!view) { + return nullptr; + } SkRect tempSubset; - const SkRect* subset = nullptr; - if (filterConstraint == kYes_FilterConstraint) { - subset = &constraintRect; - } else if (!view.proxy()->isFullyLazy() && !view.proxy()->isFunctionallyExact()) { + if (!subset && !view.proxy()->isFullyLazy() && !view.proxy()->isFunctionallyExact()) { tempSubset = view.proxy()->getBoundsRect(); subset = &tempSubset; } const auto& caps = *fContext->priv().caps(); - if (filterOrNullForBicubic) { - GrSamplerState samplerState(wrapX, wrapY, *filterOrNullForBicubic); - if (subset) { - if (coordsLimitedToConstraintRect) { - return GrTextureEffect::MakeSubset(std::move(view), this->alphaType(), - textureMatrix, samplerState, *subset, - constraintRect, caps); - } else { - return GrTextureEffect::MakeSubset(std::move(view), this->alphaType(), - textureMatrix, samplerState, *subset, caps); - } + if (subset) { + if (domain) { + return GrTextureEffect::MakeSubset(std::move(view), this->alphaType(), textureMatrix, + samplerState, *subset, *domain, caps); } else { - return GrTextureEffect::Make(std::move(view), this->alphaType(), textureMatrix, - samplerState, caps); + return GrTextureEffect::MakeSubset(std::move(view), this->alphaType(), textureMatrix, + samplerState, *subset, caps); } } else { - static constexpr auto kDir = GrBicubicEffect::Direction::kXY; - static constexpr auto kKernel = GrBicubicEffect::Kernel::kMitchell; - if (subset) { - if (coordsLimitedToConstraintRect) { - return GrBicubicEffect::MakeSubset(std::move(view), this->alphaType(), - textureMatrix, wrapX, wrapY, *subset, - constraintRect, kKernel, kDir, caps); - } else { - return GrBicubicEffect::MakeSubset(std::move(view), this->alphaType(), - textureMatrix, wrapX, wrapY, *subset, kKernel, - kDir, caps); - } + return GrTextureEffect::Make(std::move(view), this->alphaType(), textureMatrix, + samplerState, caps); + } +} + +std::unique_ptr GrTextureProducer::createBicubicFragmentProcessorForView( + GrSurfaceProxyView view, + const SkMatrix& textureMatrix, + const SkRect* subset, + const SkRect* domain, + GrSamplerState::WrapMode wrapX, + GrSamplerState::WrapMode wrapY) { + if (!view) { + return nullptr; + } + SkRect tempSubset; + + if (!subset && !view.proxy()->isFullyLazy() && !view.proxy()->isFunctionallyExact()) { + tempSubset = view.proxy()->getBoundsRect(); + subset = &tempSubset; + } + + const auto& caps = *fContext->priv().caps(); + static constexpr auto kDir = GrBicubicEffect::Direction::kXY; + static constexpr auto kKernel = GrBicubicEffect::Kernel::kMitchell; + if (subset) { + if (domain) { + return GrBicubicEffect::MakeSubset(std::move(view), this->alphaType(), textureMatrix, + wrapX, wrapY, *subset, *domain, kKernel, kDir, caps); } else { - return GrBicubicEffect::Make(std::move(view), this->alphaType(), textureMatrix, wrapX, - wrapY, kKernel, kDir, caps); + return GrBicubicEffect::MakeSubset(std::move(view), this->alphaType(), textureMatrix, + wrapX, wrapY, *subset, kKernel, kDir, caps); } + } else { + return GrBicubicEffect::Make(std::move(view), this->alphaType(), textureMatrix, wrapX, + wrapY, kKernel, kDir, caps); } } diff --git a/src/gpu/GrTextureProducer.h b/src/gpu/GrTextureProducer.h index 657553e9c9..f97605e9cb 100644 --- a/src/gpu/GrTextureProducer.h +++ b/src/gpu/GrTextureProducer.h @@ -34,39 +34,52 @@ class GrTextureProducer : public SkNoncopyable { public: virtual ~GrTextureProducer() = default; - enum FilterConstraint { - kYes_FilterConstraint, - kNo_FilterConstraint, - }; - - /** + /** * Helper for creating a fragment processor to sample the texture with a given filtering mode. - * It attempts to avoid making texture copies or using shader tiling whenever possible. + * Attempts to avoid unnecessary copies (e.g. for planar sources or subsets) by generating more + * complex shader code. * * @param textureMatrix Matrix used to access the texture. It is applied to * the local coords. The post-transformed coords should * be in texel units (rather than normalized) with * respect to this Producer's bounds (width()/height()). - * @param constraintRect A rect that represents the area of the texture to be - * sampled. It must be contained in the Producer's - * bounds as defined by width()/height(). - * @param filterConstriant Indicates whether filtering is limited to - * constraintRect. - * @param coordsLimitedToConstraintRect Is it known that textureMatrix*localCoords is bound - * by the portion of the texture indicated by - * constraintRect (without consideration of filter - * width, just the raw coords). - * @param filterOrNullForBicubic If non-null indicates the filter mode. If null means - * use bicubic filtering. + * @param subset If not null, a subset of the texture to restrict + * sampling to. The wrap modes apply to this subset. + * @param domain If not null, a known limit on the texture coordinates + * that will be accessed. Applies after textureMatrix. + * @param sampler Sampler state. Wrap modes applies to subset if not + * null, otherwise to the entire source. **/ virtual std::unique_ptr createFragmentProcessor( const SkMatrix& textureMatrix, - const SkRect& constraintRect, - FilterConstraint filterConstraint, - bool coordsLimitedToConstraintRect, + const SkRect* subset, + const SkRect* domain, + GrSamplerState sampler) = 0; + + /** + * Similar createFragmentProcessor but produces a fragment processor that does bicubic + * interpolation of the source. Attempts to avoid unnecessary copies (e.g. for planar sources or + * subsets) by generating more complex shader code. + * + * @param textureMatrix Matrix used to access the texture. It is applied to + * the local coords. The post-transformed coords should + * be in texel units (rather than normalized) with + * respect to this Producer's bounds (width()/height()). + * @param subset If not null, a subset of the texture to restrict + * sampling to. The wrap modes apply to this subset. + * @param domain If not null, a known limit on the texture coordinates + * that will be accessed. Applies after textureMatrix. + * @param wrapX Wrap mode on x axis. Applied to subset if not null, + * otherwise to the entire source. + * @param wrapY Wrap mode on y axis. Applied to subset if not null, + * otherwise to the entire source. + */ + virtual std::unique_ptr createBicubicFragmentProcessor( + const SkMatrix& textureMatrix, + const SkRect* subset, + const SkRect* domain, GrSamplerState::WrapMode wrapX, - GrSamplerState::WrapMode wrapY, - const GrSamplerState::Filter* filterOrNullForBicubic) = 0; + GrSamplerState::WrapMode wrapY) = 0; /** * Returns a texture view, possibly with MIP maps. The request for MIP maps may not be honored @@ -92,15 +105,22 @@ protected: GrTextureProducer(GrRecordingContext* context, const GrImageInfo& imageInfo) : fContext(context), fImageInfo(imageInfo) {} - std::unique_ptr createFragmentProcessorForSubsetAndFilter( + // Helper for making a texture effect from a single proxy view. + std::unique_ptr createFragmentProcessorForView( GrSurfaceProxyView view, const SkMatrix& textureMatrix, - bool coordsLimitedToConstraintRect, - FilterConstraint filterConstraint, - const SkRect& constraintRect, + const SkRect* subset, + const SkRect* domain, + GrSamplerState sampler); + + // Helper for making a bicubic effect from a single proxy view. + std::unique_ptr createBicubicFragmentProcessorForView( + GrSurfaceProxyView view, + const SkMatrix& textureMatrix, + const SkRect* subset, + const SkRect* domain, GrSamplerState::WrapMode wrapX, - GrSamplerState::WrapMode wrapY, - const GrSamplerState::Filter* filterOrNullForBicubic); + GrSamplerState::WrapMode wrapY); GrRecordingContext* context() const { return fContext; } diff --git a/src/gpu/SkGpuDevice_drawTexture.cpp b/src/gpu/SkGpuDevice_drawTexture.cpp index b6fd72dd86..08017ea79d 100644 --- a/src/gpu/SkGpuDevice_drawTexture.cpp +++ b/src/gpu/SkGpuDevice_drawTexture.cpp @@ -436,14 +436,8 @@ static void draw_texture_producer(GrRecordingContext* context, if (mf && as_MFB(mf)->hasFragmentProcessor()) { mf = nullptr; } - const GrSamplerState::Filter* filterMode = doBicubic ? nullptr : &fm; - GrTextureProducer::FilterConstraint constraintMode; - if (SkCanvas::kFast_SrcRectConstraint == constraint) { - constraintMode = GrTextureAdjuster::kNo_FilterConstraint; - } else { - constraintMode = GrTextureAdjuster::kYes_FilterConstraint; - } + bool restrictToSubset = SkCanvas::kStrict_SrcRectConstraint == constraint; // If we have to outset for AA then we will generate texture coords outside the src rect. The // same happens for any mask filter that extends the bounds rendered in the dst. @@ -451,13 +445,12 @@ static void draw_texture_producer(GrRecordingContext* context, bool coordsAllInsideSrcRect = aaFlags == GrQuadAAFlags::kNone && !mf; // Check for optimization to drop the src rect constraint when on bilerp. - if (filterMode && GrSamplerState::Filter::kBilerp == *filterMode && - GrTextureAdjuster::kYes_FilterConstraint == constraintMode && coordsAllInsideSrcRect && - !producer->isPlanar()) { + if (!doBicubic && fm == GrSamplerState::Filter::kBilerp && restrictToSubset && + coordsAllInsideSrcRect && !producer->isPlanar()) { SkMatrix combinedMatrix; combinedMatrix.setConcat(ctm, srcToDst); if (can_ignore_bilerp_constraint(*producer, src, combinedMatrix, rtc->numSamples())) { - constraintMode = GrTextureAdjuster::kNo_FilterConstraint; + restrictToSubset = false; } } @@ -469,8 +462,14 @@ static void draw_texture_producer(GrRecordingContext* context, return; } } - auto fp = producer->createFragmentProcessor(textureMatrix, src, constraintMode, - coordsAllInsideSrcRect, wm, wm, filterMode); + const SkRect* subset = restrictToSubset ? &src : nullptr; + const SkRect* domain = coordsAllInsideSrcRect ? &src : nullptr; + std::unique_ptr fp; + if (doBicubic) { + fp = producer->createBicubicFragmentProcessor(textureMatrix, subset, domain, wm, wm); + } else { + fp = producer->createFragmentProcessor(textureMatrix, subset, domain, {wm, fm}); + } fp = GrColorSpaceXformEffect::Make(std::move(fp), producer->colorSpace(), producer->alphaType(), rtc->colorInfo().colorSpace(), kPremul_SkAlphaType); diff --git a/src/gpu/effects/GrTextureEffect.cpp b/src/gpu/effects/GrTextureEffect.cpp index ff3e38a123..62ba4f7f3d 100644 --- a/src/gpu/effects/GrTextureEffect.cpp +++ b/src/gpu/effects/GrTextureEffect.cpp @@ -265,11 +265,12 @@ std::unique_ptr GrTextureEffect::MakeBilerpWithInset( GrSamplerState::WrapMode wx, GrSamplerState::WrapMode wy, const SkRect& subset, + const SkRect* domain, SkVector inset, const GrCaps& caps, const float border[4]) { GrSamplerState sampler(wx, wy, GrSamplerState::Filter::kBilerp); - Sampling sampling(*view.proxy(), sampler, subset, nullptr, border, caps, inset); + Sampling sampling(*view.proxy(), sampler, subset, domain, border, caps, inset); SkMatrix final; bool lazyProxyNormalization; get_matrix(matrix, view, &final, &lazyProxyNormalization); diff --git a/src/gpu/effects/GrTextureEffect.h b/src/gpu/effects/GrTextureEffect.h index 4692063d47..e85ed7f484 100644 --- a/src/gpu/effects/GrTextureEffect.h +++ b/src/gpu/effects/GrTextureEffect.h @@ -74,7 +74,8 @@ public: * subset. When subset is an integer rectangle this clamping avoids the hw bilerp filtering from * reading texels just outside the subset rect. This factory allows a custom inset clamping * distance rather than 0.5, allowing those neighboring texels to influence the bilerped sample - * result. + * result. If there is a known restriction on the post-matrix texture coords it can be specified + * using domain. */ static std::unique_ptr MakeBilerpWithInset( GrSurfaceProxyView, @@ -83,6 +84,7 @@ public: GrSamplerState::WrapMode wx, GrSamplerState::WrapMode wy, const SkRect& subset, + const SkRect* domain, SkVector inset, const GrCaps& caps, const float border[4] = kDefaultBorder); diff --git a/src/gpu/effects/GrYUVtoRGBEffect.cpp b/src/gpu/effects/GrYUVtoRGBEffect.cpp index 242deb5fe6..f92ec59349 100644 --- a/src/gpu/effects/GrYUVtoRGBEffect.cpp +++ b/src/gpu/effects/GrYUVtoRGBEffect.cpp @@ -36,7 +36,8 @@ std::unique_ptr GrYUVtoRGBEffect::Make(GrSurfaceProxyView v GrSamplerState samplerState, const GrCaps& caps, const SkMatrix& localMatrix, - const SkRect* subset) { + const SkRect* subset, + const SkRect* domain) { int numPlanes; SkAssertResult(SkYUVAIndex::AreValidIndices(yuvaIndices, &numPlanes)); @@ -56,6 +57,7 @@ std::unique_ptr GrYUVtoRGBEffect::Make(GrSurfaceProxyView v SkISize dimensions = views[i].proxy()->dimensions(); SkTCopyOnFirstWrite planeMatrix(&SkMatrix::I()); SkRect planeSubset; + SkRect planeDomain; bool makeBilerpWithSnap = false; float sx = 1.f, sy = 1.f; @@ -73,6 +75,19 @@ std::unique_ptr GrYUVtoRGBEffect::Make(GrSurfaceProxyView v dimensions.height() == yDimensions.height() / 2 + 1) { sy = 0.5f; } + *planeMatrix.writable() = SkMatrix::Scale(sx, sy); + if (subset) { + planeSubset = {subset->fLeft * sx, + subset->fTop * sy, + subset->fRight * sx, + subset->fBottom * sy}; + } + if (domain) { + planeDomain = {domain->fLeft * sx, + domain->fTop * sy, + domain->fRight * sx, + domain->fBottom * sy}; + } // This promotion of nearest to bilinear for UV planes exists to mimic libjpeg[-turbo]'s // do_fancy_upsampling option. We will filter the subsampled plane, however we want to // filter at a fixed point for each logical image pixel to simulate nearest neighbor. @@ -82,18 +97,25 @@ std::unique_ptr GrYUVtoRGBEffect::Make(GrSurfaceProxyView v makeBilerpWithSnap = snapX || snapY; snap[0] |= snapX; snap[1] |= snapY; + if (domain) { + // The outer YUVToRGB effect will ensure sampling happens at pixel centers + // within this plane. + planeDomain = {std::floor(planeDomain.fLeft) + 0.5f, + std::floor(planeDomain.fTop) + 0.5f, + std::floor(planeDomain.fRight) + 0.5f, + std::floor(planeDomain.fBottom) + 0.5f}; + } } - *planeMatrix.writable() = SkMatrix::Scale(sx, sy); + } else { if (subset) { - planeSubset = {subset->fLeft * sx, - subset->fTop * sy, - subset->fRight * sx, - subset->fBottom * sy}; + planeSubset = *subset; + } + if (domain) { + planeDomain = *domain; } - } else if (subset) { - planeSubset = *subset; } if (subset) { + SkASSERT(samplerState.filter() != GrSamplerState::Filter::kMipMap); if (makeBilerpWithSnap) { // The plane is subsampled and we have an overall subset on the image. We're // emulating do_fancy_upsampling using bilerp but snapping look ups to the y-plane @@ -104,10 +126,15 @@ std::unique_ptr GrYUVtoRGBEffect::Make(GrSurfaceProxyView v // we use this custom inset factory which applies the wrap mode to planeSubset but // allows the bilerp sampling to read pixels from the plane that are just outside // planeSubset. + SkRect* domainRect = domain ? &planeDomain : nullptr; planeFPs[i] = GrTextureEffect::MakeBilerpWithInset( views[i], kUnknown_SkAlphaType, *planeMatrix, samplerState.wrapModeX(), - samplerState.wrapModeY(), planeSubset, {sx/2.f, sy/2.f}, caps, + samplerState.wrapModeY(), planeSubset, domainRect, {sx/2.f, sy/2.f}, caps, planeBorders[i]); + } else if (domain) { + planeFPs[i] = GrTextureEffect::MakeSubset(views[i], kUnknown_SkAlphaType, + *planeMatrix, samplerState, planeSubset, + planeDomain, caps, planeBorders[i]); } else { SkASSERT(samplerState.filter() != GrSamplerState::Filter::kMipMap); planeFPs[i] = GrTextureEffect::MakeSubset(views[i], kUnknown_SkAlphaType, diff --git a/src/gpu/effects/GrYUVtoRGBEffect.h b/src/gpu/effects/GrYUVtoRGBEffect.h index d92dce7820..469b353fb3 100644 --- a/src/gpu/effects/GrYUVtoRGBEffect.h +++ b/src/gpu/effects/GrYUVtoRGBEffect.h @@ -21,7 +21,8 @@ public: GrSamplerState samplerState, const GrCaps&, const SkMatrix& localMatrix = SkMatrix::I(), - const SkRect* subset = nullptr); + const SkRect* subset = nullptr, + const SkRect* domain = nullptr); #ifdef SK_DEBUG SkString dumpInfo() const override; #endif diff --git a/src/shaders/SkImageShader.cpp b/src/shaders/SkImageShader.cpp index 95ef5b5861..30927f4ce1 100755 --- a/src/shaders/SkImageShader.cpp +++ b/src/shaders/SkImageShader.cpp @@ -302,20 +302,22 @@ std::unique_ptr SkImageShader::asFragmentProcessor( // quality setting. This completely ignores the complexity of the drawVertices case // where explicit local coords are provided by the caller. bool doBicubic; - GrSamplerState::Filter textureFilterMode = GrSkFilterQualityToGrFilterMode( + GrSamplerState::Filter fm = GrSkFilterQualityToGrFilterMode( fImage->width(), fImage->height(), this->resolveFiltering(args.fFilterQuality), args.fMatrixProvider.localToDevice(), *lm, args.fContext->priv().options().fSharpenMipmappedTextures, &doBicubic); - const GrSamplerState::Filter* filterOrNull = doBicubic ? nullptr : &textureFilterMode; - auto fp = producer->createFragmentProcessor(lmInverse, SkRect::Make(fImage->dimensions()), - GrTextureProducer::kNo_FilterConstraint, false, wmX, - wmY, filterOrNull); + std::unique_ptr fp; + if (doBicubic) { + fp = producer->createBicubicFragmentProcessor(lmInverse, nullptr, nullptr, wmX, wmY); + } else { + fp = producer->createFragmentProcessor(lmInverse, nullptr, nullptr, {wmX, wmY, fm}); + } + fp = GrColorSpaceXformEffect::Make(std::move(fp), fImage->colorSpace(), producer->alphaType(), + args.fDstColorInfo->colorSpace(), kPremul_SkAlphaType); if (!fp) { return nullptr; } - fp = GrColorSpaceXformEffect::Make(std::move(fp), fImage->colorSpace(), producer->alphaType(), - args.fDstColorInfo->colorSpace(), kPremul_SkAlphaType); bool isAlphaOnly = SkColorTypeIsAlphaOnly(fImage->colorType()); if (isAlphaOnly) { return fp;