Fix PixelCopy readback
Apply correct texture transform and use filter if source and dest
have different size.
Test: Ran and passed CtsUiRenderingTestCases,
Test: CtsGraphicsTestCases, CtsViewTestCases tests and the
Test: DecodeAccuracyTest.
Bug:68051015
Change-Id: Iee885e243e43497c9294f7475c0c5b9c1a783754
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
index 75967e9..b286392 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
@@ -84,57 +84,50 @@
sk_sp<SkImage> image(SkImage::MakeFromAdoptedTexture(grContext.get(), backendTexture,
kTopLeft_GrSurfaceOrigin));
if (image) {
- // Convert imgTransform matrix from right to left handed coordinate system.
- // If we have a matrix transformation in right handed coordinate system
- //|ScaleX, SkewX, TransX| same transform in left handed is |ScaleX, SkewX, TransX |
- //|SkewY, ScaleY, TransY| |-SkewY, -ScaleY, 1-TransY|
- //|0, 0, 1 | |0, 0, 1 |
- SkMatrix textureMatrix;
- textureMatrix.setIdentity();
- textureMatrix[SkMatrix::kMScaleX] = imgTransform[Matrix4::kScaleX];
- textureMatrix[SkMatrix::kMScaleY] = -imgTransform[Matrix4::kScaleY];
- textureMatrix[SkMatrix::kMSkewX] = imgTransform[Matrix4::kSkewX];
- textureMatrix[SkMatrix::kMSkewY] = -imgTransform[Matrix4::kSkewY];
- textureMatrix[SkMatrix::kMTransX] = imgTransform[Matrix4::kTranslateX];
- textureMatrix[SkMatrix::kMTransY] = 1-imgTransform[Matrix4::kTranslateY];
-
- // textureMatrix maps 2D texture coordinates of the form (s, t, 1) with s and t in the
- // inclusive range [0, 1] to the texture (see GLConsumer::getTransformMatrix comments).
- // Convert textureMatrix to translate in real texture dimensions. Texture width and
- // height are affected by the orientation (width and height swapped for 90/270 rotation).
- if (textureMatrix[SkMatrix::kMSkewX] >= 0.5f || textureMatrix[SkMatrix::kMSkewX] <= -0.5f) {
- textureMatrix[SkMatrix::kMTransX] *= imgHeight;
- textureMatrix[SkMatrix::kMTransY] *= imgWidth;
- } else {
- textureMatrix[SkMatrix::kMTransX] *= imgWidth;
- textureMatrix[SkMatrix::kMTransY] *= imgHeight;
+ int displayedWidth = imgWidth, displayedHeight = imgHeight;
+ // If this is a 90 or 270 degree rotation we need to swap width/height to get the device
+ // size.
+ if (imgTransform[Matrix4::kSkewX] >= 0.5f || imgTransform[Matrix4::kSkewX] <= -0.5f) {
+ std::swap(displayedWidth, displayedHeight);
}
-
- // convert to Skia data structures
- SkRect skiaSrcRect = srcRect.toSkRect();
- SkMatrix textureMatrixInv;
SkRect skiaDestRect = SkRect::MakeWH(bitmap->width(), bitmap->height());
- bool srcNotEmpty = false;
- if (textureMatrix.invert(&textureMatrixInv)) {
- if (skiaSrcRect.isEmpty()) {
- skiaSrcRect = SkRect::MakeIWH(imgWidth, imgHeight);
- srcNotEmpty = !skiaSrcRect.isEmpty();
- } else {
- // src and dest rectangles need to be converted into texture coordinates before the
- // rotation matrix is applied (because drawImageRect preconcat its matrix).
- textureMatrixInv.mapRect(&skiaSrcRect);
- srcNotEmpty = skiaSrcRect.intersect(SkRect::MakeIWH(imgWidth, imgHeight));
- }
- textureMatrixInv.mapRect(&skiaDestRect);
+ SkRect skiaSrcRect = srcRect.toSkRect();
+ if (skiaSrcRect.isEmpty()) {
+ skiaSrcRect = SkRect::MakeIWH(displayedWidth, displayedHeight);
}
+ bool srcNotEmpty = skiaSrcRect.intersect(SkRect::MakeIWH(displayedWidth, displayedHeight));
if (srcNotEmpty) {
+ SkMatrix textureMatrixInv;
+ imgTransform.copyTo(textureMatrixInv);
+ //TODO: after skia bug https://bugs.chromium.org/p/skia/issues/detail?id=7075 is fixed
+ // use bottom left origin and remove flipV and invert transformations.
+ SkMatrix flipV;
+ flipV.setAll(1, 0, 0, 0, -1, 1, 0, 0, 1);
+ textureMatrixInv.preConcat(flipV);
+ textureMatrixInv.preScale(1.0f/displayedWidth, 1.0f/displayedHeight);
+ textureMatrixInv.postScale(imgWidth, imgHeight);
+ SkMatrix textureMatrix;
+ if (!textureMatrixInv.invert(&textureMatrix)) {
+ textureMatrix = textureMatrixInv;
+ }
+
+ textureMatrixInv.mapRect(&skiaSrcRect);
+ textureMatrixInv.mapRect(&skiaDestRect);
+
// we render in an offscreen buffer to scale and to avoid an issue b/62262733
// with reading incorrect data from EGLImage backed SkImage (likely a driver bug)
sk_sp<SkSurface> scaledSurface = SkSurface::MakeRenderTarget(
grContext.get(), SkBudgeted::kYes, bitmap->info());
SkPaint paint;
paint.setBlendMode(SkBlendMode::kSrc);
+ // Apply a filter, which is matching OpenGL pipeline readback behaviour. Filter usage
+ // is codified by tests using golden images like DecodeAccuracyTest.
+ if (skiaSrcRect.width() != bitmap->width()
+ || skiaSrcRect.height() != bitmap->height()) {
+ //TODO: apply filter always, but check if tests will be fine
+ paint.setFilterQuality(kLow_SkFilterQuality);
+ }
scaledSurface->getCanvas()->concat(textureMatrix);
scaledSurface->getCanvas()->drawImageRect(image, skiaSrcRect, skiaDestRect, &paint,
SkCanvas::kFast_SrcRectConstraint);