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(
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<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) {
fp = GrColorSpaceXformEffect::Make(std::move(fp),
fImage->fFromColorSpace.get(), fImage->alphaType(),

View File

@ -35,14 +35,17 @@ class GrYUVAImageTextureMaker final : public GrTextureMaker {
public:
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 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; }

View File

@ -77,29 +77,19 @@ GrSurfaceProxyView GrTextureAdjuster::onView(GrMipMapped mipMapped) {
std::unique_ptr<GrFragmentProcessor> 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<GrFragmentProcessor> 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);
}

View File

@ -23,14 +23,17 @@ public:
GrTextureAdjuster(GrRecordingContext*, GrSurfaceProxyView, const GrColorInfo&,
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 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;

View File

@ -24,28 +24,20 @@ GrSurfaceProxyView GrTextureMaker::onView(GrMipMapped mipMapped) {
std::unique_ptr<GrFragmentProcessor> 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<GrFragmentProcessor> 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);
}

View File

@ -16,14 +16,17 @@
*/
class GrTextureMaker : public GrTextureProducer {
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 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)

View File

@ -20,58 +20,68 @@
#include "src/gpu/effects/GrBicubicEffect.h"
#include "src/gpu/effects/GrTextureEffect.h"
std::unique_ptr<GrFragmentProcessor> GrTextureProducer::createFragmentProcessorForSubsetAndFilter(
std::unique_ptr<GrFragmentProcessor> 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<GrFragmentProcessor> 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);
}
}

View File

@ -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<GrFragmentProcessor> 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<GrFragmentProcessor> 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<GrFragmentProcessor> createFragmentProcessorForSubsetAndFilter(
// Helper for making a texture effect from a single proxy view.
std::unique_ptr<GrFragmentProcessor> 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<GrFragmentProcessor> 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; }

View File

@ -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<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),
producer->colorSpace(), producer->alphaType(),
rtc->colorInfo().colorSpace(), kPremul_SkAlphaType);

View File

@ -265,11 +265,12 @@ std::unique_ptr<GrFragmentProcessor> 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);

View File

@ -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<GrFragmentProcessor> 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);

View File

@ -36,7 +36,8 @@ std::unique_ptr<GrFragmentProcessor> 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<GrFragmentProcessor> GrYUVtoRGBEffect::Make(GrSurfaceProxyView v
SkISize dimensions = views[i].proxy()->dimensions();
SkTCopyOnFirstWrite<SkMatrix> planeMatrix(&SkMatrix::I());
SkRect planeSubset;
SkRect planeDomain;
bool makeBilerpWithSnap = false;
float sx = 1.f,
sy = 1.f;
@ -73,6 +75,19 @@ std::unique_ptr<GrFragmentProcessor> 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<GrFragmentProcessor> 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<GrFragmentProcessor> 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,

View File

@ -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

View File

@ -302,20 +302,22 @@ std::unique_ptr<GrFragmentProcessor> 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<GrFragmentProcessor> 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;