diff options
Diffstat (limited to 'libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp')
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp | 58 |
1 files changed, 35 insertions, 23 deletions
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp index 89697d7445c6..311419dd2b65 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp @@ -20,6 +20,7 @@ #include "Properties.h" #include <SkCanvas.h> #include <SkSurface.h> +#include <GrBackendSurface.h> #include <gl/GrGLInterface.h> #include <gl/GrGLTypes.h> #include <GLES2/gl2.h> @@ -53,50 +54,61 @@ CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4 externalTexture.fTarget = GL_TEXTURE_EXTERNAL_OES; externalTexture.fID = sourceTexId; - GrBackendTextureDesc textureDescription; - textureDescription.fWidth = imgWidth; - textureDescription.fHeight = imgHeight; - textureDescription.fConfig = kRGBA_8888_GrPixelConfig; - textureDescription.fOrigin = kTopLeft_GrSurfaceOrigin; - textureDescription.fTextureHandle = reinterpret_cast<GrBackendObject>(&externalTexture); + GrBackendTexture backendTexture(imgWidth, imgHeight, kRGBA_8888_GrPixelConfig, externalTexture); CopyResult copyResult = CopyResult::UnknownError; - sk_sp<SkImage> image(SkImage::MakeFromAdoptedTexture(grContext.get(), textureDescription)); + sk_sp<SkImage> image(SkImage::MakeFromAdoptedTexture(grContext.get(), backendTexture, + kTopLeft_GrSurfaceOrigin)); if (image) { - // convert to Skia data structures - const SkRect bufferRect = SkRect::MakeIWH(imgWidth, imgHeight); - SkRect skiaSrcRect = srcRect.toSkRect(); SkMatrix textureMatrix; imgTransform.copyTo(textureMatrix); - // remove the y-flip applied to the matrix so that we can scale the srcRect. - // This flip is not needed as we specify the origin of the texture when we - // wrap it as an SkImage. + // remove the y-flip applied to the matrix SkMatrix yFlip = SkMatrix::MakeScale(1, -1); yFlip.postTranslate(0,1); textureMatrix.preConcat(yFlip); - // copy the entire src if the rect is empty - if (skiaSrcRect.isEmpty()) { - skiaSrcRect = bufferRect; - } + // multiply by image size, because textureMatrix maps to [0..1] range + textureMatrix[SkMatrix::kMTransX] *= imgWidth; + textureMatrix[SkMatrix::kMTransY] *= imgHeight; - // since the y-flip has been removed we can simply scale & translate - // the source rectangle - textureMatrix.mapRect(&skiaSrcRect); + // swap rotation and translation part of the matrix, because we convert from + // right-handed Cartesian to left-handed coordinate system. + std::swap(textureMatrix[SkMatrix::kMTransX], textureMatrix[SkMatrix::kMTransY]); + std::swap(textureMatrix[SkMatrix::kMSkewX], textureMatrix[SkMatrix::kMSkewY]); - if (skiaSrcRect.intersect(bufferRect)) { + // 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); + } + + if (srcNotEmpty) { // 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); - scaledSurface->getCanvas()->drawImageRect(image, skiaSrcRect, - SkRect::MakeWH(bitmap->width(), bitmap->height()), &paint); + scaledSurface->getCanvas()->concat(textureMatrix); + scaledSurface->getCanvas()->drawImageRect(image, skiaSrcRect, skiaDestRect, &paint); + image = scaledSurface->makeImageSnapshot(); if (image->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) { + bitmap->notifyPixelsChanged(); copyResult = CopyResult::Success; } } |