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 <michaelludwig@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Brian Salomon 2020-07-14 10:43:42 -04:00 committed by Skia Commit-Bot
parent 252a3c0e11
commit 0ea330703e
14 changed files with 249 additions and 198 deletions

View File

@ -60,50 +60,48 @@ GrSurfaceProxyView GrYUVAImageTextureMaker::refOriginalTextureProxyView(GrMipMap
std::unique_ptr<GrFragmentProcessor> GrYUVAImageTextureMaker::createFragmentProcessor( std::unique_ptr<GrFragmentProcessor> GrYUVAImageTextureMaker::createFragmentProcessor(
const SkMatrix& textureMatrix, const SkMatrix& textureMatrix,
const SkRect& constraintRect, const SkRect* subset,
FilterConstraint filterConstraint, const SkRect* domain,
bool coordsLimitedToConstraintRect, GrSamplerState samplerState) {
GrSamplerState::WrapMode wrapX,
GrSamplerState::WrapMode wrapY,
const GrSamplerState::Filter* filterOrNullForBicubic) {
// Check whether it's already been flattened. // Check whether it's already been flattened.
if (fImage->fRGBView.proxy()) { if (fImage->fRGBView.proxy()) {
return this->INHERITED::createFragmentProcessor( return this->INHERITED::createFragmentProcessor(textureMatrix, subset, domain,
textureMatrix, constraintRect, filterConstraint, coordsLimitedToConstraintRect, samplerState);
wrapX, wrapY, filterOrNullForBicubic);
} }
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 // 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 not, fall back to bilerp. Also fall back to bilerp when a domain is requested
if (GrSamplerState::Filter::kMipMap == filter && if (samplerState.filter() == GrSamplerState::Filter::kMipMap &&
(filterConstraint == GrTextureProducer::kYes_FilterConstraint || (subset || !fImage->setupMipmapsForPlanes(this->context()))) {
!fImage->setupMipmapsForPlanes(this->context()))) { samplerState.setFilterMode(GrSamplerState::Filter::kBilerp);
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;
} }
const auto& caps = *fImage->context()->priv().caps(); 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, auto fp = GrYUVtoRGBEffect::Make(fImage->fViews, fImage->fYUVAIndices, fImage->fYUVColorSpace,
sampler, caps, m, domain); samplerState, caps, textureMatrix, subset, domain);
if (!filterOrNullForBicubic) { if (fImage->fFromColorSpace) {
fp = GrBicubicEffect::Make(std::move(fp), fp = GrColorSpaceXformEffect::Make(std::move(fp), fImage->fFromColorSpace.get(),
fImage->alphaType(), fImage->alphaType(), fImage->colorSpace(),
textureMatrix, kPremul_SkAlphaType);
GrBicubicEffect::Kernel::kMitchell,
GrBicubicEffect::Direction::kXY);
} }
return fp;
}
std::unique_ptr<GrFragmentProcessor> 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) { if (fImage->fFromColorSpace) {
fp = GrColorSpaceXformEffect::Make(std::move(fp), fp = GrColorSpaceXformEffect::Make(std::move(fp),
fImage->fFromColorSpace.get(), fImage->alphaType(), fImage->fFromColorSpace.get(), fImage->alphaType(),

View File

@ -35,14 +35,17 @@ class GrYUVAImageTextureMaker final : public GrTextureMaker {
public: public:
GrYUVAImageTextureMaker(GrRecordingContext* context, const SkImage* client); GrYUVAImageTextureMaker(GrRecordingContext* context, const SkImage* client);
std::unique_ptr<GrFragmentProcessor> createFragmentProcessor( std::unique_ptr<GrFragmentProcessor> createFragmentProcessor(const SkMatrix& textureMatrix,
const SkRect* subset,
const SkRect* domain,
GrSamplerState) override;
std::unique_ptr<GrFragmentProcessor> createBicubicFragmentProcessor(
const SkMatrix& textureMatrix, const SkMatrix& textureMatrix,
const SkRect& constraintRect, const SkRect* subset,
FilterConstraint filterConstraint, const SkRect* domain,
bool coordsLimitedToConstraintRect,
GrSamplerState::WrapMode wrapX, GrSamplerState::WrapMode wrapX,
GrSamplerState::WrapMode wrapY, GrSamplerState::WrapMode wrapY) override;
const GrSamplerState::Filter* filterOrNullForBicubic) override;
bool isPlanar() const override { return true; } bool isPlanar() const override { return true; }

View File

@ -77,29 +77,19 @@ GrSurfaceProxyView GrTextureAdjuster::onView(GrMipMapped mipMapped) {
std::unique_ptr<GrFragmentProcessor> GrTextureAdjuster::createFragmentProcessor( std::unique_ptr<GrFragmentProcessor> GrTextureAdjuster::createFragmentProcessor(
const SkMatrix& textureMatrix, const SkMatrix& textureMatrix,
const SkRect& constraintRect, const SkRect* subset,
FilterConstraint filterConstraint, const SkRect* domain,
bool coordsLimitedToConstraintRect, GrSamplerState samplerState) {
GrSamplerState::WrapMode wrapX, return this->createFragmentProcessorForView(
GrSamplerState::WrapMode wrapY, this->view(samplerState.filter()), textureMatrix, subset, domain, samplerState);
const GrSamplerState::Filter* filterOrNullForBicubic) { }
GrSurfaceProxyView view;
if (filterOrNullForBicubic) { std::unique_ptr<GrFragmentProcessor> GrTextureAdjuster::createBicubicFragmentProcessor(
view = this->view(*filterOrNullForBicubic); const SkMatrix& textureMatrix,
} else { const SkRect* subset,
view = this->view(GrMipMapped::kNo); const SkRect* domain,
} GrSamplerState::WrapMode wrapX,
if (!view) { GrSamplerState::WrapMode wrapY) {
return nullptr; return this->createBicubicFragmentProcessorForView(
} this->view(GrMipMapped::kNo), textureMatrix, subset, domain, wrapX, wrapY);
SkASSERT(view.asTextureProxy());
return this->createFragmentProcessorForSubsetAndFilter(std::move(view),
textureMatrix,
coordsLimitedToConstraintRect,
filterConstraint,
constraintRect,
wrapX,
wrapY,
filterOrNullForBicubic);
} }

View File

@ -23,14 +23,17 @@ public:
GrTextureAdjuster(GrRecordingContext*, GrSurfaceProxyView, const GrColorInfo&, GrTextureAdjuster(GrRecordingContext*, GrSurfaceProxyView, const GrColorInfo&,
uint32_t uniqueID); uint32_t uniqueID);
std::unique_ptr<GrFragmentProcessor> createFragmentProcessor( std::unique_ptr<GrFragmentProcessor> createFragmentProcessor(const SkMatrix& textureMatrix,
const SkRect* subset,
const SkRect* domain,
GrSamplerState) override;
std::unique_ptr<GrFragmentProcessor> createBicubicFragmentProcessor(
const SkMatrix& textureMatrix, const SkMatrix& textureMatrix,
const SkRect& constraintRect, const SkRect* subset,
FilterConstraint, const SkRect* domain,
bool coordsLimitedToConstraintRect,
GrSamplerState::WrapMode wrapX, GrSamplerState::WrapMode wrapX,
GrSamplerState::WrapMode wrapY, GrSamplerState::WrapMode wrapY) override;
const GrSamplerState::Filter* filterOrNullForBicubic) override;
private: private:
GrSurfaceProxyView onView(GrMipMapped) override; GrSurfaceProxyView onView(GrMipMapped) override;

View File

@ -24,28 +24,20 @@ GrSurfaceProxyView GrTextureMaker::onView(GrMipMapped mipMapped) {
std::unique_ptr<GrFragmentProcessor> GrTextureMaker::createFragmentProcessor( std::unique_ptr<GrFragmentProcessor> GrTextureMaker::createFragmentProcessor(
const SkMatrix& textureMatrix, const SkMatrix& textureMatrix,
const SkRect& constraintRect, const SkRect* subset,
FilterConstraint filterConstraint, const SkRect* domain,
bool coordsLimitedToConstraintRect, GrSamplerState sampler) {
GrSamplerState::WrapMode wrapX,
GrSamplerState::WrapMode wrapY,
const GrSamplerState::Filter* filterOrNullForBicubic) {
GrSurfaceProxyView view; GrSurfaceProxyView view;
if (filterOrNullForBicubic) { return this->createFragmentProcessorForView(
view = this->view(*filterOrNullForBicubic); this->view(sampler.filter()), textureMatrix, subset, domain, sampler);
} else { }
view = this->view(GrMipMapped::kNo);
} std::unique_ptr<GrFragmentProcessor> GrTextureMaker::createBicubicFragmentProcessor(
if (!view) { const SkMatrix& textureMatrix,
return nullptr; const SkRect* subset,
} const SkRect* domain,
GrSamplerState::WrapMode wrapX,
return this->createFragmentProcessorForSubsetAndFilter(std::move(view), GrSamplerState::WrapMode wrapY) {
textureMatrix, return this->createBicubicFragmentProcessorForView(
coordsLimitedToConstraintRect, this->view(GrMipMapped::kNo), textureMatrix, subset, domain, wrapX, wrapY);
filterConstraint,
constraintRect,
wrapX,
wrapY,
filterOrNullForBicubic);
} }

View File

@ -16,14 +16,17 @@
*/ */
class GrTextureMaker : public GrTextureProducer { class GrTextureMaker : public GrTextureProducer {
public: public:
std::unique_ptr<GrFragmentProcessor> createFragmentProcessor( std::unique_ptr<GrFragmentProcessor> createFragmentProcessor(const SkMatrix& textureMatrix,
const SkRect* subset,
const SkRect* domain,
GrSamplerState) override;
std::unique_ptr<GrFragmentProcessor> createBicubicFragmentProcessor(
const SkMatrix& textureMatrix, const SkMatrix& textureMatrix,
const SkRect& constraintRect, const SkRect* subset,
FilterConstraint filterConstraint, const SkRect* domain,
bool coordsLimitedToConstraintRect,
GrSamplerState::WrapMode wrapX, GrSamplerState::WrapMode wrapX,
GrSamplerState::WrapMode wrapY, GrSamplerState::WrapMode wrapY) override;
const GrSamplerState::Filter* filterOrNullForBicubic) override;
protected: protected:
GrTextureMaker(GrRecordingContext* context, const GrImageInfo& info) GrTextureMaker(GrRecordingContext* context, const GrImageInfo& info)

View File

@ -20,58 +20,68 @@
#include "src/gpu/effects/GrBicubicEffect.h" #include "src/gpu/effects/GrBicubicEffect.h"
#include "src/gpu/effects/GrTextureEffect.h" #include "src/gpu/effects/GrTextureEffect.h"
std::unique_ptr<GrFragmentProcessor> GrTextureProducer::createFragmentProcessorForSubsetAndFilter( std::unique_ptr<GrFragmentProcessor> GrTextureProducer::createFragmentProcessorForView(
GrSurfaceProxyView view, GrSurfaceProxyView view,
const SkMatrix& textureMatrix, const SkMatrix& textureMatrix,
bool coordsLimitedToConstraintRect, const SkRect* subset,
FilterConstraint filterConstraint, const SkRect* domain,
const SkRect& constraintRect, GrSamplerState samplerState) {
GrSamplerState::WrapMode wrapX, if (!view) {
GrSamplerState::WrapMode wrapY, return nullptr;
const GrSamplerState::Filter* filterOrNullForBicubic) { }
SkRect tempSubset; SkRect tempSubset;
const SkRect* subset = nullptr; if (!subset && !view.proxy()->isFullyLazy() && !view.proxy()->isFunctionallyExact()) {
if (filterConstraint == kYes_FilterConstraint) {
subset = &constraintRect;
} else if (!view.proxy()->isFullyLazy() && !view.proxy()->isFunctionallyExact()) {
tempSubset = view.proxy()->getBoundsRect(); tempSubset = view.proxy()->getBoundsRect();
subset = &tempSubset; subset = &tempSubset;
} }
const auto& caps = *fContext->priv().caps(); const auto& caps = *fContext->priv().caps();
if (filterOrNullForBicubic) { if (subset) {
GrSamplerState samplerState(wrapX, wrapY, *filterOrNullForBicubic); if (domain) {
if (subset) { return GrTextureEffect::MakeSubset(std::move(view), this->alphaType(), textureMatrix,
if (coordsLimitedToConstraintRect) { samplerState, *subset, *domain, caps);
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);
}
} else { } else {
return GrTextureEffect::Make(std::move(view), this->alphaType(), textureMatrix, return GrTextureEffect::MakeSubset(std::move(view), this->alphaType(), textureMatrix,
samplerState, caps); samplerState, *subset, caps);
} }
} else { } else {
static constexpr auto kDir = GrBicubicEffect::Direction::kXY; return GrTextureEffect::Make(std::move(view), this->alphaType(), textureMatrix,
static constexpr auto kKernel = GrBicubicEffect::Kernel::kMitchell; samplerState, caps);
if (subset) { }
if (coordsLimitedToConstraintRect) { }
return GrBicubicEffect::MakeSubset(std::move(view), this->alphaType(),
textureMatrix, wrapX, wrapY, *subset, std::unique_ptr<GrFragmentProcessor> GrTextureProducer::createBicubicFragmentProcessorForView(
constraintRect, kKernel, kDir, caps); GrSurfaceProxyView view,
} else { const SkMatrix& textureMatrix,
return GrBicubicEffect::MakeSubset(std::move(view), this->alphaType(), const SkRect* subset,
textureMatrix, wrapX, wrapY, *subset, kKernel, const SkRect* domain,
kDir, caps); 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 { } else {
return GrBicubicEffect::Make(std::move(view), this->alphaType(), textureMatrix, wrapX, return GrBicubicEffect::MakeSubset(std::move(view), this->alphaType(), textureMatrix,
wrapY, kKernel, kDir, caps); wrapX, wrapY, *subset, kKernel, kDir, caps);
} }
} else {
return GrBicubicEffect::Make(std::move(view), this->alphaType(), textureMatrix, wrapX,
wrapY, kKernel, kDir, caps);
} }
} }

View File

@ -34,39 +34,52 @@ class GrTextureProducer : public SkNoncopyable {
public: public:
virtual ~GrTextureProducer() = default; virtual ~GrTextureProducer() = default;
enum FilterConstraint { /**
kYes_FilterConstraint,
kNo_FilterConstraint,
};
/**
* Helper for creating a fragment processor to sample the texture with a given filtering mode. * 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 * @param textureMatrix Matrix used to access the texture. It is applied to
* the local coords. The post-transformed coords should * the local coords. The post-transformed coords should
* be in texel units (rather than normalized) with * be in texel units (rather than normalized) with
* respect to this Producer's bounds (width()/height()). * respect to this Producer's bounds (width()/height()).
* @param constraintRect A rect that represents the area of the texture to be * @param subset If not null, a subset of the texture to restrict
* sampled. It must be contained in the Producer's * sampling to. The wrap modes apply to this subset.
* bounds as defined by width()/height(). * @param domain If not null, a known limit on the texture coordinates
* @param filterConstriant Indicates whether filtering is limited to * that will be accessed. Applies after textureMatrix.
* constraintRect. * @param sampler Sampler state. Wrap modes applies to subset if not
* @param coordsLimitedToConstraintRect Is it known that textureMatrix*localCoords is bound * null, otherwise to the entire source.
* 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.
**/ **/
virtual std::unique_ptr<GrFragmentProcessor> createFragmentProcessor( virtual std::unique_ptr<GrFragmentProcessor> createFragmentProcessor(
const SkMatrix& textureMatrix, const SkMatrix& textureMatrix,
const SkRect& constraintRect, const SkRect* subset,
FilterConstraint filterConstraint, const SkRect* domain,
bool coordsLimitedToConstraintRect, 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<GrFragmentProcessor> createBicubicFragmentProcessor(
const SkMatrix& textureMatrix,
const SkRect* subset,
const SkRect* domain,
GrSamplerState::WrapMode wrapX, GrSamplerState::WrapMode wrapX,
GrSamplerState::WrapMode wrapY, GrSamplerState::WrapMode wrapY) = 0;
const GrSamplerState::Filter* filterOrNullForBicubic) = 0;
/** /**
* Returns a texture view, possibly with MIP maps. The request for MIP maps may not be honored * 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) GrTextureProducer(GrRecordingContext* context, const GrImageInfo& imageInfo)
: fContext(context), fImageInfo(imageInfo) {} : fContext(context), fImageInfo(imageInfo) {}
std::unique_ptr<GrFragmentProcessor> createFragmentProcessorForSubsetAndFilter( // Helper for making a texture effect from a single proxy view.
std::unique_ptr<GrFragmentProcessor> createFragmentProcessorForView(
GrSurfaceProxyView view, GrSurfaceProxyView view,
const SkMatrix& textureMatrix, const SkMatrix& textureMatrix,
bool coordsLimitedToConstraintRect, const SkRect* subset,
FilterConstraint filterConstraint, const SkRect* domain,
const SkRect& constraintRect, GrSamplerState sampler);
// Helper for making a bicubic effect from a single proxy view.
std::unique_ptr<GrFragmentProcessor> createBicubicFragmentProcessorForView(
GrSurfaceProxyView view,
const SkMatrix& textureMatrix,
const SkRect* subset,
const SkRect* domain,
GrSamplerState::WrapMode wrapX, GrSamplerState::WrapMode wrapX,
GrSamplerState::WrapMode wrapY, GrSamplerState::WrapMode wrapY);
const GrSamplerState::Filter* filterOrNullForBicubic);
GrRecordingContext* context() const { return fContext; } GrRecordingContext* context() const { return fContext; }

View File

@ -436,14 +436,8 @@ static void draw_texture_producer(GrRecordingContext* context,
if (mf && as_MFB(mf)->hasFragmentProcessor()) { if (mf && as_MFB(mf)->hasFragmentProcessor()) {
mf = nullptr; mf = nullptr;
} }
const GrSamplerState::Filter* filterMode = doBicubic ? nullptr : &fm;
GrTextureProducer::FilterConstraint constraintMode; bool restrictToSubset = SkCanvas::kStrict_SrcRectConstraint == constraint;
if (SkCanvas::kFast_SrcRectConstraint == constraint) {
constraintMode = GrTextureAdjuster::kNo_FilterConstraint;
} else {
constraintMode = GrTextureAdjuster::kYes_FilterConstraint;
}
// If we have to outset for AA then we will generate texture coords outside the src rect. The // 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. // 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; bool coordsAllInsideSrcRect = aaFlags == GrQuadAAFlags::kNone && !mf;
// Check for optimization to drop the src rect constraint when on bilerp. // Check for optimization to drop the src rect constraint when on bilerp.
if (filterMode && GrSamplerState::Filter::kBilerp == *filterMode && if (!doBicubic && fm == GrSamplerState::Filter::kBilerp && restrictToSubset &&
GrTextureAdjuster::kYes_FilterConstraint == constraintMode && coordsAllInsideSrcRect && coordsAllInsideSrcRect && !producer->isPlanar()) {
!producer->isPlanar()) {
SkMatrix combinedMatrix; SkMatrix combinedMatrix;
combinedMatrix.setConcat(ctm, srcToDst); combinedMatrix.setConcat(ctm, srcToDst);
if (can_ignore_bilerp_constraint(*producer, src, combinedMatrix, rtc->numSamples())) { 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; return;
} }
} }
auto fp = producer->createFragmentProcessor(textureMatrix, src, constraintMode, const SkRect* subset = restrictToSubset ? &src : nullptr;
coordsAllInsideSrcRect, wm, wm, filterMode); const SkRect* domain = coordsAllInsideSrcRect ? &src : nullptr;
std::unique_ptr<GrFragmentProcessor> 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), fp = GrColorSpaceXformEffect::Make(std::move(fp),
producer->colorSpace(), producer->alphaType(), producer->colorSpace(), producer->alphaType(),
rtc->colorInfo().colorSpace(), kPremul_SkAlphaType); rtc->colorInfo().colorSpace(), kPremul_SkAlphaType);

View File

@ -265,11 +265,12 @@ std::unique_ptr<GrFragmentProcessor> GrTextureEffect::MakeBilerpWithInset(
GrSamplerState::WrapMode wx, GrSamplerState::WrapMode wx,
GrSamplerState::WrapMode wy, GrSamplerState::WrapMode wy,
const SkRect& subset, const SkRect& subset,
const SkRect* domain,
SkVector inset, SkVector inset,
const GrCaps& caps, const GrCaps& caps,
const float border[4]) { const float border[4]) {
GrSamplerState sampler(wx, wy, GrSamplerState::Filter::kBilerp); 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; SkMatrix final;
bool lazyProxyNormalization; bool lazyProxyNormalization;
get_matrix(matrix, view, &final, &lazyProxyNormalization); get_matrix(matrix, view, &final, &lazyProxyNormalization);

View File

@ -74,7 +74,8 @@ public:
* subset. When subset is an integer rectangle this clamping avoids the hw bilerp filtering from * 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 * 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 * 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<GrFragmentProcessor> MakeBilerpWithInset( static std::unique_ptr<GrFragmentProcessor> MakeBilerpWithInset(
GrSurfaceProxyView, GrSurfaceProxyView,
@ -83,6 +84,7 @@ public:
GrSamplerState::WrapMode wx, GrSamplerState::WrapMode wx,
GrSamplerState::WrapMode wy, GrSamplerState::WrapMode wy,
const SkRect& subset, const SkRect& subset,
const SkRect* domain,
SkVector inset, SkVector inset,
const GrCaps& caps, const GrCaps& caps,
const float border[4] = kDefaultBorder); const float border[4] = kDefaultBorder);

View File

@ -36,7 +36,8 @@ std::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::Make(GrSurfaceProxyView v
GrSamplerState samplerState, GrSamplerState samplerState,
const GrCaps& caps, const GrCaps& caps,
const SkMatrix& localMatrix, const SkMatrix& localMatrix,
const SkRect* subset) { const SkRect* subset,
const SkRect* domain) {
int numPlanes; int numPlanes;
SkAssertResult(SkYUVAIndex::AreValidIndices(yuvaIndices, &numPlanes)); SkAssertResult(SkYUVAIndex::AreValidIndices(yuvaIndices, &numPlanes));
@ -56,6 +57,7 @@ std::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::Make(GrSurfaceProxyView v
SkISize dimensions = views[i].proxy()->dimensions(); SkISize dimensions = views[i].proxy()->dimensions();
SkTCopyOnFirstWrite<SkMatrix> planeMatrix(&SkMatrix::I()); SkTCopyOnFirstWrite<SkMatrix> planeMatrix(&SkMatrix::I());
SkRect planeSubset; SkRect planeSubset;
SkRect planeDomain;
bool makeBilerpWithSnap = false; bool makeBilerpWithSnap = false;
float sx = 1.f, float sx = 1.f,
sy = 1.f; sy = 1.f;
@ -73,6 +75,19 @@ std::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::Make(GrSurfaceProxyView v
dimensions.height() == yDimensions.height() / 2 + 1) { dimensions.height() == yDimensions.height() / 2 + 1) {
sy = 0.5f; 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 // 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 // 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. // filter at a fixed point for each logical image pixel to simulate nearest neighbor.
@ -82,18 +97,25 @@ std::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::Make(GrSurfaceProxyView v
makeBilerpWithSnap = snapX || snapY; makeBilerpWithSnap = snapX || snapY;
snap[0] |= snapX; snap[0] |= snapX;
snap[1] |= snapY; 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) { if (subset) {
planeSubset = {subset->fLeft * sx, planeSubset = *subset;
subset->fTop * sy, }
subset->fRight * sx, if (domain) {
subset->fBottom * sy}; planeDomain = *domain;
} }
} else if (subset) {
planeSubset = *subset;
} }
if (subset) { if (subset) {
SkASSERT(samplerState.filter() != GrSamplerState::Filter::kMipMap);
if (makeBilerpWithSnap) { if (makeBilerpWithSnap) {
// The plane is subsampled and we have an overall subset on the image. We're // 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 // emulating do_fancy_upsampling using bilerp but snapping look ups to the y-plane
@ -104,10 +126,15 @@ std::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::Make(GrSurfaceProxyView v
// we use this custom inset factory which applies the wrap mode to planeSubset but // 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 // allows the bilerp sampling to read pixels from the plane that are just outside
// planeSubset. // planeSubset.
SkRect* domainRect = domain ? &planeDomain : nullptr;
planeFPs[i] = GrTextureEffect::MakeBilerpWithInset( planeFPs[i] = GrTextureEffect::MakeBilerpWithInset(
views[i], kUnknown_SkAlphaType, *planeMatrix, samplerState.wrapModeX(), 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]); planeBorders[i]);
} else if (domain) {
planeFPs[i] = GrTextureEffect::MakeSubset(views[i], kUnknown_SkAlphaType,
*planeMatrix, samplerState, planeSubset,
planeDomain, caps, planeBorders[i]);
} else { } else {
SkASSERT(samplerState.filter() != GrSamplerState::Filter::kMipMap); SkASSERT(samplerState.filter() != GrSamplerState::Filter::kMipMap);
planeFPs[i] = GrTextureEffect::MakeSubset(views[i], kUnknown_SkAlphaType, planeFPs[i] = GrTextureEffect::MakeSubset(views[i], kUnknown_SkAlphaType,

View File

@ -21,7 +21,8 @@ public:
GrSamplerState samplerState, GrSamplerState samplerState,
const GrCaps&, const GrCaps&,
const SkMatrix& localMatrix = SkMatrix::I(), const SkMatrix& localMatrix = SkMatrix::I(),
const SkRect* subset = nullptr); const SkRect* subset = nullptr,
const SkRect* domain = nullptr);
#ifdef SK_DEBUG #ifdef SK_DEBUG
SkString dumpInfo() const override; SkString dumpInfo() const override;
#endif #endif

View File

@ -302,20 +302,22 @@ std::unique_ptr<GrFragmentProcessor> SkImageShader::asFragmentProcessor(
// quality setting. This completely ignores the complexity of the drawVertices case // quality setting. This completely ignores the complexity of the drawVertices case
// where explicit local coords are provided by the caller. // where explicit local coords are provided by the caller.
bool doBicubic; bool doBicubic;
GrSamplerState::Filter textureFilterMode = GrSkFilterQualityToGrFilterMode( GrSamplerState::Filter fm = GrSkFilterQualityToGrFilterMode(
fImage->width(), fImage->height(), this->resolveFiltering(args.fFilterQuality), fImage->width(), fImage->height(), this->resolveFiltering(args.fFilterQuality),
args.fMatrixProvider.localToDevice(), *lm, args.fMatrixProvider.localToDevice(), *lm,
args.fContext->priv().options().fSharpenMipmappedTextures, &doBicubic); args.fContext->priv().options().fSharpenMipmappedTextures, &doBicubic);
const GrSamplerState::Filter* filterOrNull = doBicubic ? nullptr : &textureFilterMode; std::unique_ptr<GrFragmentProcessor> fp;
auto fp = producer->createFragmentProcessor(lmInverse, SkRect::Make(fImage->dimensions()), if (doBicubic) {
GrTextureProducer::kNo_FilterConstraint, false, wmX, fp = producer->createBicubicFragmentProcessor(lmInverse, nullptr, nullptr, wmX, wmY);
wmY, filterOrNull); } 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) { if (!fp) {
return nullptr; return nullptr;
} }
fp = GrColorSpaceXformEffect::Make(std::move(fp), fImage->colorSpace(), producer->alphaType(),
args.fDstColorInfo->colorSpace(), kPremul_SkAlphaType);
bool isAlphaOnly = SkColorTypeIsAlphaOnly(fImage->colorType()); bool isAlphaOnly = SkColorTypeIsAlphaOnly(fImage->colorType());
if (isAlphaOnly) { if (isAlphaOnly) {
return fp; return fp;