Index: src/gpu/SkGpuDevice_drawTexture.cpp |
diff --git a/src/gpu/SkGpuDevice_drawTexture.cpp b/src/gpu/SkGpuDevice_drawTexture.cpp |
index b41d69c6fd7aa5f690c18bb27fb4de2834235985..ccc9e2a2dd0da91dc8763c2fedee02d6e073b888 100644 |
--- a/src/gpu/SkGpuDevice_drawTexture.cpp |
+++ b/src/gpu/SkGpuDevice_drawTexture.cpp |
@@ -52,7 +52,71 @@ static const GrFragmentProcessor* mix_texture_fp_with_paint_color_and_shader( |
} |
} |
-void SkGpuDevice::drawTextureAdjuster(GrTextureAdjuster* adjuster, |
+////////////////////////////////////////////////////////////////////////////// |
+// Helper functions for dropping src rect constraint in bilerp mode. |
+ |
+static const SkScalar kColorBleedTolerance = 0.001f; |
+ |
+static bool has_aligned_samples(const SkRect& srcRect, const SkRect& transformedRect) { |
+ // detect pixel disalignment |
+ if (SkScalarAbs(SkScalarFraction(transformedRect.left())) < kColorBleedTolerance && |
+ SkScalarAbs(SkScalarFraction(transformedRect.top())) < kColorBleedTolerance && |
+ SkScalarAbs(transformedRect.width() - srcRect.width()) < kColorBleedTolerance && |
+ SkScalarAbs(transformedRect.height() - srcRect.height()) < kColorBleedTolerance) { |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+static bool may_color_bleed(const SkRect& srcRect, |
+ const SkRect& transformedRect, |
+ const SkMatrix& m, |
+ bool isMSAA) { |
+ // Only gets called if has_aligned_samples returned false. |
+ // So we can assume that sampling is axis aligned but not texel aligned. |
+ SkASSERT(!has_aligned_samples(srcRect, transformedRect)); |
+ SkRect innerSrcRect(srcRect), innerTransformedRect, outerTransformedRect(transformedRect); |
+ if (isMSAA) { |
+ innerSrcRect.inset(SK_Scalar1, SK_Scalar1); |
+ } else { |
+ innerSrcRect.inset(SK_ScalarHalf, SK_ScalarHalf); |
+ } |
+ m.mapRect(&innerTransformedRect, innerSrcRect); |
+ |
+ // The gap between outerTransformedRect and innerTransformedRect |
+ // represents the projection of the source border area, which is |
+ // problematic for color bleeding. We must check whether any |
+ // destination pixels sample the border area. |
+ outerTransformedRect.inset(kColorBleedTolerance, kColorBleedTolerance); |
+ innerTransformedRect.outset(kColorBleedTolerance, kColorBleedTolerance); |
+ SkIRect outer, inner; |
+ outerTransformedRect.round(&outer); |
+ innerTransformedRect.round(&inner); |
+ // If the inner and outer rects round to the same result, it means the |
+ // border does not overlap any pixel centers. Yay! |
+ return inner != outer; |
+} |
+ |
+static bool can_ignore_bilerp_constraint(const GrTextureProducer& producer, |
+ const SkRect& srcRect, |
+ const SkMatrix& srcRectToDeviceSpace, |
+ bool isMSAA) { |
+ if (srcRectToDeviceSpace.rectStaysRect()) { |
+ // sampling is axis-aligned |
+ SkRect transformedRect; |
+ srcRectToDeviceSpace.mapRect(&transformedRect, srcRect); |
+ |
+ if (has_aligned_samples(srcRect, transformedRect) || |
+ !may_color_bleed(srcRect, transformedRect, srcRectToDeviceSpace, isMSAA)) { |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
+////////////////////////////////////////////////////////////////////////////// |
+ |
+void SkGpuDevice::drawTextureProducer(GrTextureProducer* producer, |
bool alphaOnly, |
const SkRect* srcRect, |
const SkRect* dstRect, |
@@ -65,7 +129,7 @@ void SkGpuDevice::drawTextureAdjuster(GrTextureAdjuster* adjuster, |
// the matrix that maps the src rect to the dst rect. |
SkRect clippedSrcRect; |
SkRect clippedDstRect; |
- const SkRect srcBounds = SkRect::MakeIWH(adjuster->width(), adjuster->height()); |
+ const SkRect srcBounds = SkRect::MakeIWH(producer->width(), producer->height()); |
SkMatrix srcToDstMatrix; |
if (srcRect) { |
if (!dstRect) { |
@@ -100,11 +164,11 @@ void SkGpuDevice::drawTextureAdjuster(GrTextureAdjuster* adjuster, |
} |
} |
- this->drawTextureAdjusterImpl(adjuster, alphaOnly, clippedSrcRect, clippedDstRect, constraint, |
+ this->drawTextureProducerImpl(producer, alphaOnly, clippedSrcRect, clippedDstRect, constraint, |
viewMatrix, srcToDstMatrix, clip, paint); |
} |
-void SkGpuDevice::drawTextureAdjusterImpl(GrTextureAdjuster* adjuster, |
+void SkGpuDevice::drawTextureProducerImpl(GrTextureProducer* producer, |
bool alphaTexture, |
const SkRect& clippedSrcRect, |
const SkRect& clippedDstRect, |
@@ -141,6 +205,17 @@ void SkGpuDevice::drawTextureAdjusterImpl(GrTextureAdjuster* adjuster, |
// This is conservative as a mask filter does not have to expand the bounds rendered. |
bool coordsAllInsideSrcRect = !paint.isAntiAlias() && !mf; |
+ // Check for optimization to drop the src rect constraint when on bilerp. |
+ if (filterMode && GrTextureParams::kBilerp_FilterMode == *filterMode && |
+ GrTextureAdjuster::kYes_FilterConstraint == constraintMode && coordsAllInsideSrcRect) { |
+ SkMatrix combinedMatrix; |
+ combinedMatrix.setConcat(viewMatrix, srcToDstMatrix); |
+ if (can_ignore_bilerp_constraint(*producer, clippedSrcRect, combinedMatrix, |
+ fRenderTarget->isUnifiedMultisampled())) { |
+ constraintMode = GrTextureAdjuster::kNo_FilterConstraint; |
+ } |
+ } |
+ |
const SkMatrix* textureMatrix; |
SkMatrix tempMatrix; |
if (canUseTextureCoordsAsLocalCoords) { |
@@ -151,7 +226,7 @@ void SkGpuDevice::drawTextureAdjusterImpl(GrTextureAdjuster* adjuster, |
} |
textureMatrix = &tempMatrix; |
} |
- SkAutoTUnref<const GrFragmentProcessor> fp(adjuster->createFragmentProcessor( |
+ SkAutoTUnref<const GrFragmentProcessor> fp(producer->createFragmentProcessor( |
*textureMatrix, clippedSrcRect, constraintMode, coordsAllInsideSrcRect, filterMode)); |
if (!fp) { |
return; |