diff options
Diffstat (limited to 'src/gpu')
-rw-r--r-- | src/gpu/GrTextureAdjuster.cpp | 76 | ||||
-rw-r--r-- | src/gpu/GrTextureAdjuster.h | 15 | ||||
-rw-r--r-- | src/gpu/GrTextureMaker.cpp | 9 | ||||
-rw-r--r-- | src/gpu/GrTextureProducer.cpp | 115 | ||||
-rw-r--r-- | src/gpu/GrTextureProducer.h | 3 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 6 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice_drawTexture.cpp | 5 |
7 files changed, 180 insertions, 49 deletions
diff --git a/src/gpu/GrTextureAdjuster.cpp b/src/gpu/GrTextureAdjuster.cpp index 1508cb578f..546ea67b60 100644 --- a/src/gpu/GrTextureAdjuster.cpp +++ b/src/gpu/GrTextureAdjuster.cpp @@ -13,14 +13,22 @@ #include "SkGr.h" GrTextureAdjuster::GrTextureAdjuster(GrContext* context, sk_sp<GrTextureProxy> original, - SkAlphaType alphaType, uint32_t uniqueID, SkColorSpace* cs) - : INHERITED(original->width(), original->height(), - GrPixelConfigIsAlphaOnly(original->config())) - , fContext(context) - , fOriginal(std::move(original)) - , fAlphaType(alphaType) - , fColorSpace(cs) - , fUniqueID(uniqueID) {} + SkAlphaType alphaType, + const SkIRect& contentArea, uint32_t uniqueID, + SkColorSpace* cs) + : INHERITED(contentArea.width(), contentArea.height(), + GrPixelConfigIsAlphaOnly(original->config())) + , fContext(context) + , fOriginal(std::move(original)) + , fAlphaType(alphaType) + , fColorSpace(cs) + , fUniqueID(uniqueID) { + SkASSERT(SkIRect::MakeWH(fOriginal->width(), fOriginal->height()).contains(contentArea)); + if (contentArea.fLeft > 0 || contentArea.fTop > 0 || + contentArea.fRight < fOriginal->width() || contentArea.fBottom < fOriginal->height()) { + fContentArea.set(contentArea); + } +} void GrTextureAdjuster::makeCopyKey(const CopyParams& params, GrUniqueKey* copyKey, SkColorSpace* dstColorSpace) { @@ -46,8 +54,9 @@ sk_sp<GrTextureProxy> GrTextureAdjuster::refTextureProxyCopy(const CopyParams& c } sk_sp<GrTextureProxy> proxy = this->originalProxyRef(); + const SkIRect* contentArea = this->contentAreaOrNull(); - sk_sp<GrTextureProxy> copy = CopyOnGpu(fContext, std::move(proxy), copyParams); + sk_sp<GrTextureProxy> copy = CopyOnGpu(fContext, std::move(proxy), contentArea, copyParams); if (copy) { if (key.isValid()) { SkASSERT(copy->origin() == this->originalProxy()->origin()); @@ -60,31 +69,60 @@ sk_sp<GrTextureProxy> GrTextureAdjuster::refTextureProxyCopy(const CopyParams& c sk_sp<GrTextureProxy> GrTextureAdjuster::refTextureProxySafeForParams( const GrSamplerParams& params, + SkIPoint* outOffset, SkScalar scaleAdjust[2]) { sk_sp<GrTextureProxy> proxy = this->originalProxyRef(); CopyParams copyParams; + const SkIRect* contentArea = this->contentAreaOrNull(); if (!fContext) { // The texture was abandoned. return nullptr; } - if (!fContext->getGpu()->isACopyNeededForTextureParams(proxy.get(), params, ©Params, - scaleAdjust)) { + + if (contentArea && GrSamplerParams::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 = GrSamplerParams::kBilerp_FilterMode; + } else if (!fContext->getGpu()->isACopyNeededForTextureParams(proxy.get(), params, ©Params, + scaleAdjust)) { + if (outOffset) { + if (contentArea) { + outOffset->set(contentArea->fLeft, contentArea->fRight); + } else { + outOffset->set(0, 0); + } + } return proxy; } sk_sp<GrTextureProxy> copy = this->refTextureProxyCopy(copyParams); + if (copy && outOffset) { + outOffset->set(0, 0); + } return copy; } std::unique_ptr<GrFragmentProcessor> GrTextureAdjuster::createFragmentProcessor( const SkMatrix& origTextureMatrix, - const SkRect& constraintRect, + const SkRect& origConstraintRect, FilterConstraint filterConstraint, bool coordsLimitedToConstraintRect, const GrSamplerParams::FilterMode* filterOrNullForBicubic, SkColorSpace* dstColorSpace) { SkMatrix textureMatrix = origTextureMatrix; + const SkIRect* contentArea = this->contentAreaOrNull(); + // Convert the constraintRect to be relative to the texture rather than the content area so + // that both rects are in the same coordinate system. + SkTCopyOnFirstWrite<SkRect> constraintRect(origConstraintRect); + if (contentArea) { + SkScalar l = SkIntToScalar(contentArea->fLeft); + SkScalar t = SkIntToScalar(contentArea->fTop); + constraintRect.writable()->offset(l, t); + textureMatrix.postTranslate(l, t); + } SkRect domain; GrSamplerParams params; @@ -92,19 +130,22 @@ std::unique_ptr<GrFragmentProcessor> GrTextureAdjuster::createFragmentProcessor( params.setFilterMode(*filterOrNullForBicubic); } SkScalar scaleAdjust[2] = { 1.0f, 1.0f }; - sk_sp<GrTextureProxy> proxy(this->refTextureProxySafeForParams(params, scaleAdjust)); + sk_sp<GrTextureProxy> proxy(this->refTextureProxySafeForParams(params, nullptr, scaleAdjust)); if (!proxy) { return nullptr; } // If we made a copy then we only copied the contentArea, in which case the new texture is all // content. if (proxy.get() != this->originalProxy()) { + contentArea = nullptr; textureMatrix.postScale(scaleAdjust[0], scaleAdjust[1]); } DomainMode domainMode = - DetermineDomainMode(constraintRect, filterConstraint, coordsLimitedToConstraintRect, - proxy.get(), filterOrNullForBicubic, &domain); + DetermineDomainMode(*constraintRect, filterConstraint, coordsLimitedToConstraintRect, + proxy.get(), + contentArea, filterOrNullForBicubic, + &domain); if (kTightCopy_DomainMode == domainMode) { // TODO: Copy the texture and adjust the texture matrix (both parts need to consider // non-int constraint rect) @@ -115,8 +156,9 @@ std::unique_ptr<GrFragmentProcessor> GrTextureAdjuster::createFragmentProcessor( GrSamplerParams::kMipMap_FilterMode == *filterOrNullForBicubic); static const GrSamplerParams::FilterMode kBilerp = GrSamplerParams::kBilerp_FilterMode; domainMode = - DetermineDomainMode(constraintRect, filterConstraint, coordsLimitedToConstraintRect, - proxy.get(), &kBilerp, &domain); + DetermineDomainMode(*constraintRect, filterConstraint, coordsLimitedToConstraintRect, + proxy.get(), + contentArea, &kBilerp, &domain); SkASSERT(kTightCopy_DomainMode != domainMode); } SkASSERT(kNoDomain_DomainMode == domainMode || diff --git a/src/gpu/GrTextureAdjuster.h b/src/gpu/GrTextureAdjuster.h index 3c9d0fd3d4..fad533f30f 100644 --- a/src/gpu/GrTextureAdjuster.h +++ b/src/gpu/GrTextureAdjuster.h @@ -21,9 +21,10 @@ class GrTextureAdjuster : public GrTextureProducer { public: /** Makes the subset of the texture safe to use with the given texture parameters. - If the copy's size does not match subset's dimensions then the resulting scale - factors used to sample the copy are returned in 'scaleAdjust'. */ - sk_sp<GrTextureProxy> refTextureProxySafeForParams(const GrSamplerParams&, + outOffset will be the top-left corner of the subset if a copy is not made. Otherwise, + the copy will be tight to the contents and outOffset will be (0, 0). If the copy's size + does not match subset's dimensions then the contents are scaled to fit the copy.*/ + sk_sp<GrTextureProxy> refTextureProxySafeForParams(const GrSamplerParams&, SkIPoint* outOffset, SkScalar scaleAdjust[2]); std::unique_ptr<GrFragmentProcessor> createFragmentProcessor( @@ -36,8 +37,8 @@ public: // We do not ref the texture nor the colorspace, so the caller must keep them in scope while // this Adjuster is alive. - GrTextureAdjuster(GrContext*, sk_sp<GrTextureProxy>, SkAlphaType, uint32_t uniqueID, - SkColorSpace*); + GrTextureAdjuster(GrContext*, sk_sp<GrTextureProxy>, SkAlphaType, const SkIRect& area, + uint32_t uniqueID, SkColorSpace*); protected: SkAlphaType alphaType() const override { return fAlphaType; } @@ -48,7 +49,11 @@ protected: GrTextureProxy* originalProxy() const { return fOriginal.get(); } sk_sp<GrTextureProxy> originalProxyRef() const { return fOriginal; } + /** Returns the content area or null for the whole original texture */ + const SkIRect* contentAreaOrNull() { return fContentArea.getMaybeNull(); } + private: + SkTLazy<SkIRect> fContentArea; GrContext* fContext; sk_sp<GrTextureProxy> fOriginal; SkAlphaType fAlphaType; diff --git a/src/gpu/GrTextureMaker.cpp b/src/gpu/GrTextureMaker.cpp index bb30439e6e..7e257d8a78 100644 --- a/src/gpu/GrTextureMaker.cpp +++ b/src/gpu/GrTextureMaker.cpp @@ -59,7 +59,7 @@ sk_sp<GrTextureProxy> GrTextureMaker::refTextureProxyForParams(const GrSamplerPa sk_sp<GrTextureProxy> result; if (original) { - result = CopyOnGpu(fContext, std::move(original), copyParams); + result = CopyOnGpu(fContext, std::move(original), nullptr, copyParams); } else { result = this->generateTextureProxyForParams(copyParams, willBeMipped, dstColorSpace); } @@ -114,8 +114,9 @@ std::unique_ptr<GrFragmentProcessor> GrTextureMaker::createFragmentProcessor( adjustedMatrix.postScale(scaleAdjust[0], scaleAdjust[1]); SkRect domain; DomainMode domainMode = - DetermineDomainMode(constraintRect, filterConstraint, coordsLimitedToConstraintRect, - proxy.get(), fmForDetermineDomain, &domain); + DetermineDomainMode(constraintRect, filterConstraint, coordsLimitedToConstraintRect, + proxy.get(), + nullptr, fmForDetermineDomain, &domain); SkASSERT(kTightCopy_DomainMode != domainMode); sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(texColorSpace.get(), dstColorSpace); @@ -134,5 +135,5 @@ sk_sp<GrTextureProxy> GrTextureMaker::generateTextureProxyForParams(const CopyPa return nullptr; } - return CopyOnGpu(fContext, std::move(original), copyParams); + return CopyOnGpu(fContext, std::move(original), nullptr, copyParams); } diff --git a/src/gpu/GrTextureProducer.cpp b/src/gpu/GrTextureProducer.cpp index f7d71fa18d..92732238e6 100644 --- a/src/gpu/GrTextureProducer.cpp +++ b/src/gpu/GrTextureProducer.cpp @@ -16,7 +16,9 @@ sk_sp<GrTextureProxy> GrTextureProducer::CopyOnGpu(GrContext* context, sk_sp<GrTextureProxy> inputProxy, + const SkIRect* subset, const CopyParams& copyParams) { + SkASSERT(!subset || !subset->isEmpty()); SkASSERT(context); const SkRect dstRect = SkRect::MakeIWH(copyParams.fWidth, copyParams.fHeight); @@ -31,13 +33,23 @@ sk_sp<GrTextureProxy> GrTextureProducer::CopyOnGpu(GrContext* context, GrPaint paint; paint.setGammaCorrect(true); - SkRect localRect = SkRect::MakeWH(inputProxy->width(), inputProxy->height()); + SkRect localRect; + if (subset) { + localRect = SkRect::Make(*subset); + } else { + localRect = SkRect::MakeWH(inputProxy->width(), inputProxy->height()); + } bool needsDomain = false; if (copyParams.fFilter != GrSamplerParams::kNone_FilterMode) { bool resizing = localRect.width() != dstRect.width() || localRect.height() != dstRect.height(); - needsDomain = resizing && !GrResourceProvider::IsFunctionallyExact(inputProxy.get()); + + if (GrResourceProvider::IsFunctionallyExact(inputProxy.get())) { + needsDomain = subset && resizing; + } else { + needsDomain = resizing; + } } if (needsDomain) { @@ -76,45 +88,62 @@ GrTextureProducer::DomainMode GrTextureProducer::DetermineDomainMode( FilterConstraint filterConstraint, bool coordsLimitedToConstraintRect, GrTextureProxy* proxy, + const SkIRect* contentRect, const GrSamplerParams::FilterMode* filterModeOrNullForBicubic, SkRect* domainRect) { const SkIRect proxyBounds = SkIRect::MakeWH(proxy->width(), proxy->height()); SkASSERT(proxyBounds.contains(constraintRect)); + // We only expect a content area rect if there is some non-content area. + SkASSERT(!contentRect || + (!contentRect->contains(proxyBounds) && + proxyBounds.contains(*contentRect) && + contentRect->contains(constraintRect))); const bool proxyIsExact = GrResourceProvider::IsFunctionallyExact(proxy); - // We don't expect to have an image that is in an inexact proxy unless the caller was aware - // of the potential of sampling outside of the proxy's bounds and specified a constraint rect - // with a filter constraint. - SkASSERT(kYes_FilterConstraint == filterConstraint || proxyIsExact); + // If the constraint rectangle contains the whole proxy then no need for a domain. if (constraintRect.contains(proxyBounds) && proxyIsExact) { return kNoDomain_DomainMode; } + if (!contentRect && !proxyIsExact) { + contentRect = &proxyBounds; + } + bool restrictFilterToRect = (filterConstraint == GrTextureProducer::kYes_FilterConstraint); // If we can filter outside the constraint rect, and there is no non-content area of the // proxy, and we aren't going to generate sample coords outside the constraint rect then we // don't need a domain. - if (!restrictFilterToRect && coordsLimitedToConstraintRect) { + if (!restrictFilterToRect && !contentRect && coordsLimitedToConstraintRect) { return kNoDomain_DomainMode; } // Get the domain inset based on sampling mode (or bail if mipped) + SkScalar filterHalfWidth = 0.f; if (filterModeOrNullForBicubic) { switch (*filterModeOrNullForBicubic) { case GrSamplerParams::kNone_FilterMode: if (coordsLimitedToConstraintRect) { return kNoDomain_DomainMode; + } else { + filterHalfWidth = 0.f; } break; case GrSamplerParams::kBilerp_FilterMode: + filterHalfWidth = .5f; break; case GrSamplerParams::kMipMap_FilterMode: - // No domain can save us with mip maps. - return restrictFilterToRect ? kTightCopy_DomainMode : kNoDomain_DomainMode; + if (restrictFilterToRect || contentRect) { + // No domain can save us here. + return kTightCopy_DomainMode; + } + return kNoDomain_DomainMode; } + } else { + // bicubic does nearest filtering internally. + filterHalfWidth = 1.5f; } // Both bilerp and bicubic use bilinear filtering and so need to be clamped to the center @@ -126,17 +155,67 @@ GrTextureProducer::DomainMode GrTextureProducer::DetermineDomainMode( // the domain. if (restrictFilterToRect) { *domainRect = constraintRect.makeInset(kDomainInset, kDomainInset); - if (domainRect->fLeft > domainRect->fRight) { - domainRect->fLeft = domainRect->fRight = - SkScalarAve(domainRect->fLeft, domainRect->fRight); - } - if (domainRect->fTop > domainRect->fBottom) { - domainRect->fTop = domainRect->fBottom = - SkScalarAve(domainRect->fTop, domainRect->fBottom); + } else if (contentRect) { + // If we got here then: there is a contentRect, the coords are limited to the + // constraint rect, and we're allowed to filter across the constraint rect boundary. So + // we check whether the filter would reach across the edge of the content area. + // We will only set the sides that are required. + + domainRect->setLargest(); + if (coordsLimitedToConstraintRect) { + // We may be able to use the fact that the texture coords are limited to the constraint + // rect in order to avoid having to add a domain. + bool needContentAreaConstraint = false; + if (contentRect->fLeft > 0 && + contentRect->fLeft + filterHalfWidth > constraintRect.fLeft) { + domainRect->fLeft = contentRect->fLeft + kDomainInset; + needContentAreaConstraint = true; + } + if (contentRect->fTop > 0 && + contentRect->fTop + filterHalfWidth > constraintRect.fTop) { + domainRect->fTop = contentRect->fTop + kDomainInset; + needContentAreaConstraint = true; + } + if ((!proxyIsExact || contentRect->fRight < proxy->width()) && + contentRect->fRight - filterHalfWidth < constraintRect.fRight) { + domainRect->fRight = contentRect->fRight - kDomainInset; + needContentAreaConstraint = true; + } + if ((!proxyIsExact || contentRect->fBottom < proxy->height()) && + contentRect->fBottom - filterHalfWidth < constraintRect.fBottom) { + domainRect->fBottom = contentRect->fBottom - kDomainInset; + needContentAreaConstraint = true; + } + if (!needContentAreaConstraint) { + return kNoDomain_DomainMode; + } + } else { + // Our sample coords for the texture are allowed to be outside the constraintRect so we + // don't consider it when computing the domain. + if (contentRect->fLeft > 0) { + domainRect->fLeft = contentRect->fLeft + kDomainInset; + } + if (contentRect->fTop > 0) { + domainRect->fTop = contentRect->fTop + kDomainInset; + } + if (!proxyIsExact || contentRect->fRight < proxy->width()) { + domainRect->fRight = contentRect->fRight - kDomainInset; + } + if (!proxyIsExact || contentRect->fBottom < proxy->height()) { + domainRect->fBottom = contentRect->fBottom - kDomainInset; + } } - return kDomain_DomainMode; + } else { + return kNoDomain_DomainMode; + } + + if (domainRect->fLeft > domainRect->fRight) { + domainRect->fLeft = domainRect->fRight = SkScalarAve(domainRect->fLeft, domainRect->fRight); + } + if (domainRect->fTop > domainRect->fBottom) { + domainRect->fTop = domainRect->fBottom = SkScalarAve(domainRect->fTop, domainRect->fBottom); } - return kNoDomain_DomainMode; + return kDomain_DomainMode; } std::unique_ptr<GrFragmentProcessor> GrTextureProducer::CreateFragmentProcessorForDomainAndFilter( diff --git a/src/gpu/GrTextureProducer.h b/src/gpu/GrTextureProducer.h index 2853a88525..ccc0dae2ee 100644 --- a/src/gpu/GrTextureProducer.h +++ b/src/gpu/GrTextureProducer.h @@ -119,13 +119,14 @@ protected: }; static sk_sp<GrTextureProxy> CopyOnGpu(GrContext*, sk_sp<GrTextureProxy> inputProxy, - const CopyParams& copyParams); + const SkIRect* subset, const CopyParams& copyParams); static DomainMode DetermineDomainMode( const SkRect& constraintRect, FilterConstraint filterConstraint, bool coordsLimitedToConstraintRect, GrTextureProxy*, + const SkIRect* textureContentArea, const GrSamplerParams::FilterMode* filterModeOrNullForBicubic, SkRect* domainRect); diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index a279c92fd1..0cf2ae5893 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -1406,7 +1406,8 @@ void SkGpuDevice::drawImageNine(const SkImage* image, ASSERT_SINGLE_OWNER uint32_t pinnedUniqueID; if (sk_sp<GrTextureProxy> proxy = as_IB(image)->refPinnedTextureProxy(&pinnedUniqueID)) { - GrTextureAdjuster adjuster(this->context(), std::move(proxy), image->alphaType(), + GrTextureAdjuster adjuster(this->context(), std::move(proxy), + image->alphaType(), image->bounds(), pinnedUniqueID, as_IB(image)->onImageInfo().colorSpace()); this->drawProducerNine(&adjuster, center, dst, paint); } else { @@ -1460,7 +1461,8 @@ void SkGpuDevice::drawImageLattice(const SkImage* image, ASSERT_SINGLE_OWNER uint32_t pinnedUniqueID; if (sk_sp<GrTextureProxy> proxy = as_IB(image)->refPinnedTextureProxy(&pinnedUniqueID)) { - GrTextureAdjuster adjuster(this->context(), std::move(proxy), image->alphaType(), + GrTextureAdjuster adjuster(this->context(), std::move(proxy), + image->alphaType(), image->bounds(), pinnedUniqueID, as_IB(image)->onImageInfo().colorSpace()); this->drawProducerLattice(&adjuster, lattice, dst, paint); } else { diff --git a/src/gpu/SkGpuDevice_drawTexture.cpp b/src/gpu/SkGpuDevice_drawTexture.cpp index 596f50445c..c861cc919e 100644 --- a/src/gpu/SkGpuDevice_drawTexture.cpp +++ b/src/gpu/SkGpuDevice_drawTexture.cpp @@ -145,8 +145,9 @@ void SkGpuDevice::drawPinnedTextureProxy(sk_sp<GrTextureProxy> proxy, uint32_t p this->clip(), fRenderTargetContext.get()); return; } - GrTextureAdjuster adjuster(this->context(), std::move(proxy), alphaType, pinnedUniqueID, - colorSpace); + auto contentRect = SkIRect::MakeWH(proxy->width(), proxy->height()); + GrTextureAdjuster adjuster(this->context(), std::move(proxy), alphaType, contentRect, + pinnedUniqueID, colorSpace); this->drawTextureProducer(&adjuster, srcRect, dstRect, constraint, viewMatrix, paint); } |