Refactor HWUI readback code to be backend independent

Implement readback from Surface, TextureView and HW Bitmap
for Vulkan pipeline by wrapping the graphics buffer in an SkImage.
Refactor both Vulkan and GL readback to use common code.
TextureView readback is moved from IRenderPipeline interface to
Readback class. Refactor all 3 readback flows to use common
implementation.

Test: Passed all view, uirendering and graphics CTS tests with GL
Test: Passed many CTS test with Vulkan, that require readback
Bug: 113673613
Change-Id: Ifbfd8170a5401f87a709b4b1b9fa058e8e11768d
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index b6cd4b0..3ca0f81 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -28,12 +28,13 @@
 void LayerDrawable::onDraw(SkCanvas* canvas) {
     Layer* layer = mLayerUpdater->backingLayer();
     if (layer) {
-        DrawLayer(canvas->getGrContext(), canvas, layer);
+        DrawLayer(canvas->getGrContext(), canvas, layer, nullptr, nullptr, true);
     }
 }
 
 bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer,
-                              const SkRect* dstRect) {
+                              const SkRect* srcRect, const SkRect* dstRect,
+                              bool useLayerTransform) {
     if (context == nullptr) {
         SkDEBUGF(("Attempting to draw LayerDrawable into an unsupported surface"));
         return false;
@@ -60,12 +61,10 @@
         }
 
         SkMatrix matrix;
-        if (dstRect) {
-            // Destination rectangle is set only when we are trying to read back the content
-            // of the layer. In this case we don't want to apply layer transform.
-            matrix = textureMatrix;
-        } else {
+        if (useLayerTransform) {
             matrix = SkMatrix::Concat(layerTransform, textureMatrix);
+        } else {
+            matrix = textureMatrix;
         }
 
         SkPaint paint;
@@ -81,16 +80,26 @@
             canvas->save();
             canvas->concat(matrix);
         }
-        if (dstRect) {
+        if (dstRect || srcRect) {
             SkMatrix matrixInv;
             if (!matrix.invert(&matrixInv)) {
                 matrixInv = matrix;
             }
-            SkRect srcRect = SkRect::MakeIWH(layerWidth, layerHeight);
-            matrixInv.mapRect(&srcRect);
-            SkRect skiaDestRect = *dstRect;
+            SkRect skiaSrcRect;
+            if (srcRect) {
+                skiaSrcRect = *srcRect;
+            } else {
+                skiaSrcRect = SkRect::MakeIWH(layerWidth, layerHeight);
+            }
+            matrixInv.mapRect(&skiaSrcRect);
+            SkRect skiaDestRect;
+            if (dstRect) {
+                skiaDestRect = *dstRect;
+            } else {
+                skiaDestRect = SkRect::MakeIWH(layerWidth, layerHeight);
+            }
             matrixInv.mapRect(&skiaDestRect);
-            canvas->drawImageRect(layerImage.get(), srcRect, skiaDestRect, &paint,
+            canvas->drawImageRect(layerImage.get(), skiaSrcRect, skiaDestRect, &paint,
                                   SkCanvas::kFast_SrcRectConstraint);
         } else {
             canvas->drawImage(layerImage.get(), 0, 0, &paint);
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.h b/libs/hwui/pipeline/skia/LayerDrawable.h
index 18d1184..5c12590 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.h
+++ b/libs/hwui/pipeline/skia/LayerDrawable.h
@@ -33,7 +33,7 @@
     explicit LayerDrawable(DeferredLayerUpdater* layerUpdater) : mLayerUpdater(layerUpdater) {}
 
     static bool DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer,
-                          const SkRect* dstRect = nullptr);
+                          const SkRect* srcRect, const SkRect* dstRect, bool useLayerTransform);
 
 protected:
     virtual SkRect onGetBounds() override {
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 2ae3723..d58b59e 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -127,65 +127,6 @@
     return *requireSwap;
 }
 
-bool SkiaOpenGLPipeline::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBitmap* bitmap) {
-    if (!mRenderThread.getGrContext()) {
-        return false;
-    }
-
-    // acquire most recent buffer for drawing
-    deferredLayer->updateTexImage();
-    deferredLayer->apply();
-
-    // drop the colorSpace as we only support readback into sRGB or extended sRGB
-    SkImageInfo surfaceInfo = bitmap->info().makeColorSpace(nullptr);
-
-    /* This intermediate surface is present to work around a bug in SwiftShader that
-     * prevents us from reading the contents of the layer's texture directly. The
-     * workaround involves first rendering that texture into an intermediate buffer and
-     * then reading from the intermediate buffer into the bitmap.
-     */
-    sk_sp<SkSurface> tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(),
-                                                              SkBudgeted::kYes, surfaceInfo);
-
-    if (!tmpSurface.get()) {
-        surfaceInfo = surfaceInfo.makeColorType(SkColorType::kN32_SkColorType);
-        tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes,
-                                                 surfaceInfo);
-        if (!tmpSurface.get()) {
-            ALOGW("Unable to readback GPU contents into the provided bitmap");
-            return false;
-        }
-    }
-
-    Layer* layer = deferredLayer->backingLayer();
-    const SkRect dstRect = SkRect::MakeIWH(bitmap->width(), bitmap->height());
-    if (LayerDrawable::DrawLayer(mRenderThread.getGrContext(), tmpSurface->getCanvas(), layer,
-                                 &dstRect)) {
-        sk_sp<SkImage> tmpImage = tmpSurface->makeImageSnapshot();
-        if (tmpImage->readPixels(surfaceInfo, bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) {
-            bitmap->notifyPixelsChanged();
-            return true;
-        }
-
-        // if we fail to readback from the GPU directly (e.g. 565) then we attempt to read into 8888
-        // and then draw that into the destination format before giving up.
-        SkBitmap tmpBitmap;
-        SkImageInfo bitmapInfo =
-                SkImageInfo::MakeN32(bitmap->width(), bitmap->height(), bitmap->alphaType());
-        if (tmpBitmap.tryAllocPixels(bitmapInfo) &&
-            tmpImage->readPixels(bitmapInfo, tmpBitmap.getPixels(), tmpBitmap.rowBytes(), 0, 0)) {
-            SkCanvas canvas(*bitmap);
-            SkPaint paint;
-            paint.setBlendMode(SkBlendMode::kSrc);
-            canvas.drawBitmap(tmpBitmap, 0, 0, &paint);
-            bitmap->notifyPixelsChanged();
-            return true;
-        }
-    }
-
-    return false;
-}
-
 DeferredLayerUpdater* SkiaOpenGLPipeline::createTextureLayer() {
     mRenderThread.requireGlContext();
     return new DeferredLayerUpdater(mRenderThread.renderState());
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index 2e2e152..808685a 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -40,7 +40,6 @@
               FrameInfoVisualizer* profiler) override;
     bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
                      FrameInfo* currentFrameInfo, bool* requireSwap) override;
-    bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) override;
     DeferredLayerUpdater* createTextureLayer() override;
     bool setSurface(Surface* window, renderthread::SwapBehavior swapBehavior,
                     renderthread::ColorMode colorMode) override;
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
deleted file mode 100644
index f2f5056..0000000
--- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "SkiaOpenGLReadback.h"
-
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#include <GrBackendSurface.h>
-#include <SkCanvas.h>
-#include <SkSurface.h>
-#include <gl/GrGLInterface.h>
-#include <gl/GrGLTypes.h>
-#include "DeviceInfo.h"
-#include "Matrix.h"
-#include "Properties.h"
-#include "utils/MathUtils.h"
-
-using namespace android::uirenderer::renderthread;
-
-namespace android {
-namespace uirenderer {
-namespace skiapipeline {
-
-CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
-                                             int imgWidth, int imgHeight, const Rect& srcRect,
-                                             SkBitmap* bitmap) {
-    GLuint sourceTexId;
-    glGenTextures(1, &sourceTexId);
-    glBindTexture(GL_TEXTURE_EXTERNAL_OES, sourceTexId);
-    glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, eglImage);
-
-    sk_sp<GrContext> grContext = sk_ref_sp(mRenderThread.getGrContext());
-    if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
-        sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface());
-        LOG_ALWAYS_FATAL_IF(!glInterface.get());
-        grContext = GrContext::MakeGL(std::move(glInterface));
-    } else {
-        grContext->resetContext();
-    }
-
-    if (bitmap->colorType() == kRGBA_F16_SkColorType &&
-            !grContext->colorTypeSupportedAsSurface(bitmap->colorType())) {
-        ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported");
-        return CopyResult::DestinationInvalid;
-    }
-
-    GrGLTextureInfo externalTexture;
-    externalTexture.fTarget = GL_TEXTURE_EXTERNAL_OES;
-    externalTexture.fID = sourceTexId;
-    switch (bitmap->colorType()) {
-        case kRGBA_F16_SkColorType:
-            externalTexture.fFormat = GL_RGBA16F;
-            break;
-        case kN32_SkColorType:
-        default:
-            externalTexture.fFormat = GL_RGBA8;
-            break;
-    }
-
-    GrBackendTexture backendTexture(imgWidth, imgHeight, GrMipMapped::kNo, externalTexture);
-
-    CopyResult copyResult = CopyResult::UnknownError;
-    sk_sp<SkImage> image(SkImage::MakeFromAdoptedTexture(grContext.get(), backendTexture,
-                                                         kTopLeft_GrSurfaceOrigin,
-                                                         bitmap->colorType()));
-    if (image) {
-        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);
-        }
-        SkRect skiaDestRect = SkRect::MakeWH(bitmap->width(), bitmap->height());
-        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.
-            bool disableFilter = MathUtils::areEqual(skiaSrcRect.width(), skiaDestRect.width())
-                    && MathUtils::areEqual(skiaSrcRect.height(), skiaDestRect.height());
-            if (!disableFilter) {
-                paint.setFilterQuality(kLow_SkFilterQuality);
-            }
-            scaledSurface->getCanvas()->concat(textureMatrix);
-            scaledSurface->getCanvas()->drawImageRect(image, skiaSrcRect, skiaDestRect, &paint,
-                                                      SkCanvas::kFast_SrcRectConstraint);
-
-            image = scaledSurface->makeImageSnapshot();
-
-            if (image->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) {
-                bitmap->notifyPixelsChanged();
-                copyResult = CopyResult::Success;
-            }
-        }
-    }
-
-    // make sure that we have deleted the texture (in the SkImage) before we
-    // destroy the EGLImage that it was created from
-    image.reset();
-    glFinish();
-
-    return copyResult;
-}
-
-} /* namespace skiapipeline */
-} /* namespace uirenderer */
-} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h
deleted file mode 100644
index 1ce4773..0000000
--- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EglReadback.h"
-
-namespace android {
-namespace uirenderer {
-namespace skiapipeline {
-
-class SkiaOpenGLReadback : public EglReadback {
-public:
-    SkiaOpenGLReadback(renderthread::RenderThread& thread) : EglReadback(thread) {}
-
-protected:
-    virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
-                                     int imgWidth, int imgHeight, const Rect& srcRect,
-                                     SkBitmap* bitmap) override;
-};
-
-} /* namespace skiapipeline */
-} /* namespace uirenderer */
-} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 5f2eee4..611a34c 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -108,11 +108,6 @@
     return *requireSwap;
 }
 
-bool SkiaVulkanPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
-    // TODO: implement copyLayerInto for vulkan.
-    return false;
-}
-
 DeferredLayerUpdater* SkiaVulkanPipeline::createTextureLayer() {
     mVkManager.initialize();
 
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index 7806b42..900b054 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -38,7 +38,6 @@
               FrameInfoVisualizer* profiler) override;
     bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
                      FrameInfo* currentFrameInfo, bool* requireSwap) override;
-    bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) override;
     DeferredLayerUpdater* createTextureLayer() override;
     bool setSurface(Surface* window, renderthread::SwapBehavior swapBehavior,
                     renderthread::ColorMode colorMode) override;
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanReadback.h b/libs/hwui/pipeline/skia/SkiaVulkanReadback.h
deleted file mode 100644
index 65b89d6..0000000
--- a/libs/hwui/pipeline/skia/SkiaVulkanReadback.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "Readback.h"
-
-namespace android {
-namespace uirenderer {
-namespace skiapipeline {
-
-class SkiaVulkanReadback : public Readback {
-public:
-    SkiaVulkanReadback(renderthread::RenderThread& thread) : Readback(thread) {}
-
-    virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect,
-            SkBitmap* bitmap) override {
-        //TODO: implement Vulkan readback.
-        return CopyResult::UnknownError;
-    }
-
-    virtual CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer,
-            SkBitmap* bitmap) override {
-        //TODO: implement Vulkan readback.
-        return CopyResult::UnknownError;
-    }
-};
-
-} /* namespace skiapipeline */
-} /* namespace uirenderer */
-} /* namespace android */