From 4df0092eac6e9bb5afc516773a0c618630193dc6 Mon Sep 17 00:00:00 2001 From: Brian Salomon Date: Thu, 7 Sep 2017 16:34:11 +0000 Subject: [PATCH] Revert "Remove "content" rect from GrTextureAdjuster." This reverts commit 6e4bbbefe153495cf34ea42aa72691756e6ab40e. Reason for revert: assertion failure Original change's description: > Remove "content" rect from GrTextureAdjuster. > > Since we got rid of texture-backed bitmaps this is no longer required. > > Change-Id: Id15c745994a3d6a1489e193b5d29916fa0931264 > Reviewed-on: https://skia-review.googlesource.com/36340 > Commit-Queue: Brian Salomon > Reviewed-by: Robert Phillips TBR=bsalomon@google.com,robertphillips@google.com Change-Id: I2229ec05079368ff196ff351107f88062080e5ec No-Presubmit: true No-Tree-Checks: true No-Try: true Reviewed-on: https://skia-review.googlesource.com/43720 Reviewed-by: Brian Salomon Commit-Queue: Brian Salomon --- src/gpu/GrTextureAdjuster.cpp | 76 ++++++++++++---- src/gpu/GrTextureAdjuster.h | 15 ++-- src/gpu/GrTextureMaker.cpp | 9 +- src/gpu/GrTextureProducer.cpp | 115 ++++++++++++++++++++---- src/gpu/GrTextureProducer.h | 3 +- src/gpu/SkGpuDevice.cpp | 6 +- src/gpu/SkGpuDevice_drawTexture.cpp | 5 +- src/image/SkImage_Gpu.cpp | 6 +- src/image/SkImage_Raster.cpp | 7 +- tests/DetermineDomainModeTest.cpp | 135 +++++++++++++++++++--------- 10 files changed, 281 insertions(+), 96 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 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 GrTextureAdjuster::refTextureProxyCopy(const CopyParams& c } sk_sp proxy = this->originalProxyRef(); + const SkIRect* contentArea = this->contentAreaOrNull(); - sk_sp copy = CopyOnGpu(fContext, std::move(proxy), copyParams); + sk_sp 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 GrTextureAdjuster::refTextureProxyCopy(const CopyParams& c sk_sp GrTextureAdjuster::refTextureProxySafeForParams( const GrSamplerParams& params, + SkIPoint* outOffset, SkScalar scaleAdjust[2]) { sk_sp 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 copy = this->refTextureProxyCopy(copyParams); + if (copy && outOffset) { + outOffset->set(0, 0); + } return copy; } std::unique_ptr 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 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 GrTextureAdjuster::createFragmentProcessor( params.setFilterMode(*filterOrNullForBicubic); } SkScalar scaleAdjust[2] = { 1.0f, 1.0f }; - sk_sp proxy(this->refTextureProxySafeForParams(params, scaleAdjust)); + sk_sp 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 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 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 refTextureProxySafeForParams(const GrSamplerParams&, SkIPoint* outOffset, SkScalar scaleAdjust[2]); std::unique_ptr 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, SkAlphaType, uint32_t uniqueID, - SkColorSpace*); + GrTextureAdjuster(GrContext*, sk_sp, 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 originalProxyRef() const { return fOriginal; } + /** Returns the content area or null for the whole original texture */ + const SkIRect* contentAreaOrNull() { return fContentArea.getMaybeNull(); } + private: + SkTLazy fContentArea; GrContext* fContext; sk_sp 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 GrTextureMaker::refTextureProxyForParams(const GrSamplerPa sk_sp 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 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 colorSpaceXform = GrColorSpaceXform::Make(texColorSpace.get(), dstColorSpace); @@ -134,5 +135,5 @@ sk_sp 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 GrTextureProducer::CopyOnGpu(GrContext* context, sk_sp 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 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); + } 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; + } } - if (domainRect->fTop > domainRect->fBottom) { - domainRect->fTop = domainRect->fBottom = - SkScalarAve(domainRect->fTop, domainRect->fBottom); - } - return kDomain_DomainMode; + } else { + return kNoDomain_DomainMode; } - 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 kDomain_DomainMode; } std::unique_ptr 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 CopyOnGpu(GrContext*, sk_sp 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 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 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 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); } diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp index 034f7bc742..3458075321 100644 --- a/src/image/SkImage_Gpu.cpp +++ b/src/image/SkImage_Gpu.cpp @@ -123,9 +123,9 @@ sk_sp SkImage_Gpu::asTextureProxyRef(GrContext* context, *texColorSpace = this->fColorSpace; } - GrTextureAdjuster adjuster(fContext, fProxy, this->alphaType(), this->uniqueID(), - this->fColorSpace.get()); - return adjuster.refTextureProxySafeForParams(params, scaleAdjust); + GrTextureAdjuster adjuster(fContext, fProxy, this->alphaType(), this->bounds(), + this->uniqueID(), this->fColorSpace.get()); + return adjuster.refTextureProxySafeForParams(params, nullptr, scaleAdjust); } static void apply_premul(const SkImageInfo& info, void* pixels, size_t rowBytes) { diff --git a/src/image/SkImage_Raster.cpp b/src/image/SkImage_Raster.cpp index cb4a5b2881..5b7e83f3a7 100644 --- a/src/image/SkImage_Raster.cpp +++ b/src/image/SkImage_Raster.cpp @@ -186,9 +186,10 @@ sk_sp SkImage_Raster::asTextureProxyRef(GrContext* context, uint32_t uniqueID; sk_sp tex = this->refPinnedTextureProxy(&uniqueID); if (tex) { - GrTextureAdjuster adjuster(context, fPinnedProxy, fBitmap.alphaType(), fPinnedUniqueID, - fBitmap.colorSpace()); - return adjuster.refTextureProxySafeForParams(params, scaleAdjust); + GrTextureAdjuster adjuster(context, fPinnedProxy, + fBitmap.alphaType(), fBitmap.bounds(), + fPinnedUniqueID, fBitmap.colorSpace()); + return adjuster.refTextureProxySafeForParams(params, nullptr, scaleAdjust); } return GrRefCachedBitmapTextureProxy(context, fBitmap, params, scaleAdjust); diff --git a/tests/DetermineDomainModeTest.cpp b/tests/DetermineDomainModeTest.cpp index ef1a5ad09f..ee9a694f19 100644 --- a/tests/DetermineDomainModeTest.cpp +++ b/tests/DetermineDomainModeTest.cpp @@ -13,10 +13,11 @@ #include "GrTextureProducer.h" #include "GrTextureProxy.h" -// For DetermineDomainMode (in the MDB world) we have 3 rects: +// For DetermineDomainMode (in the MDB world) we have 4 rects: // 1) the final instantiated backing storage (i.e., the actual GrTexture's extent) // 2) the proxy's extent, which may or may not match the GrTexture's extent -// 3) the constraint rect, which can optionally be hard or soft +// 3) the content rect, which can be a subset of the proxy's extent or null +// 4) the constraint rect, which can optionally be hard or soft // This test "fuzzes" all the combinations of these rects. class GrTextureProducer_TestAccess { public: @@ -27,12 +28,14 @@ public: GrTextureProducer::FilterConstraint filterConstraint, bool coordsLimitedToConstraintRect, GrTextureProxy* proxy, + const SkIRect* textureContentArea, const GrSamplerParams::FilterMode* filterModeOrNullForBicubic, SkRect* domainRect) { return GrTextureProducer::DetermineDomainMode(constraintRect, filterConstraint, coordsLimitedToConstraintRect, proxy, + textureContentArea, filterModeOrNullForBicubic, domainRect); } @@ -40,6 +43,22 @@ public: using DomainMode = GrTextureProducer_TestAccess::DomainMode; +#ifdef SK_DEBUG +static bool is_irect(const SkRect& r) { + return SkScalarIsInt(r.fLeft) && SkScalarIsInt(r.fTop) && + SkScalarIsInt(r.fRight) && SkScalarIsInt(r.fBottom); +} +#endif + +static SkIRect to_irect(const SkRect& r) { + SkASSERT(is_irect(r)); + return SkIRect::MakeLTRB(SkScalarRoundToInt(r.fLeft), + SkScalarRoundToInt(r.fTop), + SkScalarRoundToInt(r.fRight), + SkScalarRoundToInt(r.fBottom)); +} + + class RectInfo { public: enum Side { kLeft = 0, kTop = 1, kRight = 2, kBot = 3 }; @@ -297,6 +316,20 @@ static const SkRect* full_inset(const RectInfo& enclosing, kInsetLeft_Flag|kInsetTop_Flag|kInsetRight_Flag|kInsetBot_Flag, name); } +// This is only used for content rect creation. We ensure 'result' is correct but +// return null to indicate no content area (other than what the proxy specifies). +static const SkRect* null_rect(const RectInfo& enclosing, + RectInfo* result, + bool isInsetHard, + bool areCoordsLimitedToRect, + float insetAmount, + float halfFilterWidth) { + static const char* name = "null"; + generic_inset(enclosing, result, isInsetHard, areCoordsLimitedToRect, + insetAmount, halfFilterWidth, 0, name); + return nullptr; +} + // Make a rect with no inset. This is only used for constraint rect creation. static const SkRect* no_inset(const RectInfo& enclosing, RectInfo* result, @@ -332,50 +365,70 @@ static void proxy_test(skiatest::Reporter* reporter, GrResourceProvider* resourc sk_sp proxy = create_proxy(resourceProvider, isPowerOfTwoSized, isExact, &outermost); SkASSERT(outermost.isHardOrBadAllAround()); - for (auto isConstraintRectHard : { true, false }) { - if (!isConstraintRectHard && !isExact) { - // GrTextureProducer expects that texture inexactness is expressed as a - // constraint rect and asserts if not. This skips a case that never happens - // through the public API. - continue; + + for (auto contentRectMaker : { left_only, top_only, right_only, + bot_only, full_inset, null_rect}) { + RectInfo contentRectStorage; + const SkRect* contentRect = (*contentRectMaker)(outermost, + &contentRectStorage, + true, false, 5.0f, -1.0f); + if (contentRect) { + // We only have content rects if they actually reduce the extent of the content + SkASSERT(!contentRect->contains(outermost.rect())); + SkASSERT(outermost.rect().contains(*contentRect)); + SkASSERT(is_irect(*contentRect)); } - for (auto areCoordsLimitedToConstraintRect : { true, false }) { - for (int filterMode = 0; filterMode < 4; ++filterMode) { - for (auto constraintRectMaker : { left_only, top_only, right_only, - bot_only, full_inset, no_inset }) { - for (auto insetAmt : { 0.25f, 0.75f, 1.25f, 1.75f, 5.0f }) { - RectInfo constraintRectStorage; - const SkRect* constraintRect = (*constraintRectMaker)( - outermost, - &constraintRectStorage, - isConstraintRectHard, - areCoordsLimitedToConstraintRect, - insetAmt, - gHalfFilterWidth[filterMode]); - SkASSERT(constraintRect); // always need one of these - SkASSERT(outermost.rect().contains(*constraintRect)); + SkASSERT(contentRectStorage.isHardOrBadAllAround()); - actualMode = GrTextureProducer_TestAccess::DetermineDomainMode( - *constraintRect, - isConstraintRectHard - ? GrTextureProducer::kYes_FilterConstraint - : GrTextureProducer::kNo_FilterConstraint, - areCoordsLimitedToConstraintRect, - proxy.get(), - gModePtrs[filterMode], - &actualDomainRect); - - expectedMode = DomainMode::kNoDomain_DomainMode; - if (constraintRectStorage.hasABad()) { - if (3 == filterMode) { - expectedMode = DomainMode::kTightCopy_DomainMode; + for (auto isConstraintRectHard : { true, false }) { + for (auto areCoordsLimitedToConstraintRect : { true, false }) { + for (int filterMode = 0; filterMode < 4; ++filterMode) { + for (auto constraintRectMaker : { left_only, top_only, right_only, + bot_only, full_inset, no_inset }) { + for (auto insetAmt : { 0.25f, 0.75f, 1.25f, 1.75f, 5.0f }) { + RectInfo constraintRectStorage; + const SkRect* constraintRect = (*constraintRectMaker)( + contentRect ? contentRectStorage : outermost, + &constraintRectStorage, + isConstraintRectHard, + areCoordsLimitedToConstraintRect, + insetAmt, + gHalfFilterWidth[filterMode]); + SkASSERT(constraintRect); // always need one of these + if (contentRect) { + SkASSERT(contentRect->contains(*constraintRect)); } else { - expectedMode = DomainMode::kDomain_DomainMode; + SkASSERT(outermost.rect().contains(*constraintRect)); } - } - REPORTER_ASSERT(reporter, expectedMode == actualMode); - // TODO: add a check that the returned domain rect is correct + SkIRect contentIRect; + if (contentRect) { + contentIRect = to_irect(*contentRect); + } + + actualMode = GrTextureProducer_TestAccess::DetermineDomainMode( + *constraintRect, + isConstraintRectHard + ? GrTextureProducer::kYes_FilterConstraint + : GrTextureProducer::kNo_FilterConstraint, + areCoordsLimitedToConstraintRect, + proxy.get(), + contentRect ? &contentIRect : nullptr, + gModePtrs[filterMode], + &actualDomainRect); + + expectedMode = DomainMode::kNoDomain_DomainMode; + if (constraintRectStorage.hasABad()) { + if (3 == filterMode) { + expectedMode = DomainMode::kTightCopy_DomainMode; + } else { + expectedMode = DomainMode::kDomain_DomainMode; + } + } + + REPORTER_ASSERT(reporter, expectedMode == actualMode); + // TODO: add a check that the returned domain rect is correct + } } } }