diff options
-rw-r--r-- | libs/hwui/pipeline/skia/LayerDrawable.cpp | 73 |
1 files changed, 48 insertions, 25 deletions
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp index eed19420a78a..96b17e1d7975 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.cpp +++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp @@ -33,21 +33,47 @@ void LayerDrawable::onDraw(SkCanvas* canvas) { } } -// This is a less-strict matrix.isTranslate() that will still report being translate-only -// on imperceptibly small scaleX & scaleY values. -static bool isBasicallyTranslate(const SkMatrix& matrix) { - if (!matrix.isScaleTranslate()) return false; - return MathUtils::isOne(matrix.getScaleX()) && MathUtils::isOne(matrix.getScaleY()); -} - -static bool shouldFilter(const SkMatrix& matrix) { - if (!matrix.isScaleTranslate()) return true; - - // We only care about meaningful scale here - bool noScale = MathUtils::isOne(matrix.getScaleX()) && MathUtils::isOne(matrix.getScaleY()); - bool pixelAligned = - SkScalarIsInt(matrix.getTranslateX()) && SkScalarIsInt(matrix.getTranslateY()); - return !(noScale && pixelAligned); +// Disable filtering when there is no scaling in screen coordinates and the corners have the same +// fraction (for translate) or zero fraction (for any other rect-to-rect transform). +static bool shouldFilterRect(const SkMatrix& matrix, const SkRect& srcRect, const SkRect& dstRect) { + if (!matrix.rectStaysRect()) return true; + SkRect dstDevRect = matrix.mapRect(dstRect); + float dstW, dstH; + bool requiresIntegerTranslate = false; + if (MathUtils::isZero(matrix.getScaleX()) && MathUtils::isZero(matrix.getScaleY())) { + // Has a 90 or 270 degree rotation, although total matrix may also have scale factors + // in m10 and m01. Those scalings are automatically handled by mapRect so comparing + // dimensions is sufficient, but swap width and height comparison. + dstW = dstDevRect.height(); + dstH = dstDevRect.width(); + requiresIntegerTranslate = true; + } else { + // Handle H/V flips or 180 rotation matrices. Axes may have been mirrored, but + // dimensions are still safe to compare directly. + dstW = dstDevRect.width(); + dstH = dstDevRect.height(); + requiresIntegerTranslate = + matrix.getScaleX() < -NON_ZERO_EPSILON || matrix.getScaleY() < -NON_ZERO_EPSILON; + } + if (!(MathUtils::areEqual(dstW, srcRect.width()) && + MathUtils::areEqual(dstH, srcRect.height()))) { + return true; + } + if (requiresIntegerTranslate) { + // Device rect and source rect should be integer aligned to ensure there's no difference + // in how nearest-neighbor sampling is resolved. + return !(MathUtils::isZero(SkScalarFraction(srcRect.x())) && + MathUtils::isZero(SkScalarFraction(srcRect.y())) && + MathUtils::isZero(SkScalarFraction(dstDevRect.x())) && + MathUtils::isZero(SkScalarFraction(dstDevRect.y()))); + } else { + // As long as src and device rects are translated by the same fractional amount, + // filtering won't be needed + return !(MathUtils::areEqual(SkScalarFraction(srcRect.x()), + SkScalarFraction(dstDevRect.x())) && + MathUtils::areEqual(SkScalarFraction(srcRect.y()), + SkScalarFraction(dstDevRect.y()))); + } } bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer, @@ -114,24 +140,21 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer skiaDestRect = SkRect::MakeIWH(layerWidth, layerHeight); } matrixInv.mapRect(&skiaDestRect); - // If (matrix is identity or an integer translation) and (src/dst buffers size match), + // If (matrix is a rect-to-rect transform) + // and (src/dst buffers size match in screen coordinates) + // and (src/dst corners align fractionally), // then use nearest neighbor, otherwise use bilerp sampling. - // Integer translation is defined as when src rect and dst rect align fractionally. // Skia TextureOp has the above logic build-in, but not NonAAFillRectOp. TextureOp works // only for SrcOver blending and without color filter (readback uses Src blending). - bool isIntegerTranslate = - isBasicallyTranslate(totalMatrix) && - SkScalarFraction(skiaDestRect.fLeft + totalMatrix[SkMatrix::kMTransX]) == - SkScalarFraction(skiaSrcRect.fLeft) && - SkScalarFraction(skiaDestRect.fTop + totalMatrix[SkMatrix::kMTransY]) == - SkScalarFraction(skiaSrcRect.fTop); - if (layer->getForceFilter() || !isIntegerTranslate) { + if (layer->getForceFilter() || + shouldFilterRect(totalMatrix, skiaSrcRect, skiaDestRect)) { paint.setFilterQuality(kLow_SkFilterQuality); } canvas->drawImageRect(layerImage.get(), skiaSrcRect, skiaDestRect, &paint, SkCanvas::kFast_SrcRectConstraint); } else { - if (layer->getForceFilter() || shouldFilter(totalMatrix)) { + SkRect imageRect = SkRect::MakeIWH(layerImage->width(), layerImage->height()); + if (layer->getForceFilter() || shouldFilterRect(totalMatrix, imageRect, imageRect)) { paint.setFilterQuality(kLow_SkFilterQuality); } canvas->drawImage(layerImage.get(), 0, 0, &paint); |