Support readback from hardware bitmaps

Test: hwuimacro readbackFromHBitmap --onscreen.
bug:30999911
Change-Id: I369c069c40cb0f9adae5a94501815f29c2d7df0f
diff --git a/libs/hwui/OpenGLReadback.cpp b/libs/hwui/OpenGLReadback.cpp
index da6d994..408159b 100644
--- a/libs/hwui/OpenGLReadback.cpp
+++ b/libs/hwui/OpenGLReadback.cpp
@@ -34,8 +34,6 @@
 CopyResult OpenGLReadback::copySurfaceInto(Surface& surface, const Rect& srcRect,
         SkBitmap* bitmap) {
     ATRACE_CALL();
-    mRenderThread.eglManager().initialize();
-
     // Setup the source
     sp<GraphicBuffer> sourceBuffer;
     sp<Fence> sourceFence;
@@ -61,13 +59,19 @@
         return CopyResult::Timeout;
     }
 
+    return copyGraphicBufferInto(sourceBuffer.get(), texTransform, srcRect, bitmap);
+}
+
+CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer,
+        Matrix4& texTransform, const Rect& srcRect, SkBitmap* bitmap) {
+    mRenderThread.eglManager().initialize();
     // TODO: Can't use Image helper since it forces GL_TEXTURE_2D usage via
     // GL_OES_EGL_image, which doesn't work since we need samplerExternalOES
     // to be able to properly sample from the buffer.
 
     // Create the EGLImage object that maps the GraphicBuffer
     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    EGLClientBuffer clientBuffer = (EGLClientBuffer) sourceBuffer->getNativeBuffer();
+    EGLClientBuffer clientBuffer = (EGLClientBuffer) graphicBuffer->getNativeBuffer();
     EGLint attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
 
     EGLImageKHR sourceImage = eglCreateImageKHR(display, EGL_NO_CONTEXT,
@@ -78,8 +82,8 @@
         return CopyResult::UnknownError;
     }
 
-    CopyResult copyResult = copyImageInto(sourceImage, texTransform, sourceBuffer->getWidth(),
-            sourceBuffer->getHeight(), srcRect, bitmap);
+    CopyResult copyResult = copyImageInto(sourceImage, texTransform, graphicBuffer->getWidth(),
+            graphicBuffer->getHeight(), srcRect, bitmap);
 
     // All we're flushing & finishing is the deletion of the texture since
     // copyImageInto already did a major flush & finish as an implicit
@@ -89,6 +93,14 @@
     return copyResult;
 }
 
+CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, SkBitmap* bitmap) {
+    Rect srcRect;
+    Matrix4 transform;
+    transform.loadScale(1, -1, 1);
+    transform.translate(0, -1);
+    return copyGraphicBufferInto(graphicBuffer, transform, srcRect, bitmap);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////
 
diff --git a/libs/hwui/OpenGLReadback.h b/libs/hwui/OpenGLReadback.h
index 7ec2a96..f4ebabc 100644
--- a/libs/hwui/OpenGLReadback.h
+++ b/libs/hwui/OpenGLReadback.h
@@ -28,6 +28,8 @@
 public:
     virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect,
             SkBitmap* bitmap) override;
+    virtual CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer,
+            SkBitmap* bitmap) override;
 
 protected:
     explicit OpenGLReadback(renderthread::RenderThread& thread) : Readback(thread) {}
@@ -35,6 +37,9 @@
 
     virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
             int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) = 0;
+private:
+    CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer, Matrix4& texTransform,
+            const Rect& srcRect, SkBitmap* bitmap);
 };
 
 class OpenGLReadbackImpl : public OpenGLReadback {
diff --git a/libs/hwui/Readback.h b/libs/hwui/Readback.h
index 7fbc4bf..b763953 100644
--- a/libs/hwui/Readback.h
+++ b/libs/hwui/Readback.h
@@ -23,6 +23,7 @@
 #include <gui/Surface.h>
 
 namespace android {
+class GraphicBuffer;
 namespace uirenderer {
 
 // Keep in sync with PixelCopy.java codes
@@ -42,6 +43,7 @@
      */
     virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect,
             SkBitmap* bitmap) = 0;
+    virtual CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer, SkBitmap* bitmap) = 0;
 
 protected:
     explicit Readback(renderthread::RenderThread& thread) : mRenderThread(thread) {}
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index c028f115..d6b6548 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -459,14 +459,15 @@
 }
 
 void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
+    outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
     if (isHardware()) {
-        //TODO: use readback to get pixels
-        LOG_ALWAYS_FATAL("Not implemented");
+        ALOGW("Warning: attempt to read pixels from hardware bitmap, which is very slow operation");
+        outBitmap->allocPixels(info());
+        uirenderer::renderthread::RenderProxy::copyGraphicBufferInto(graphicBuffer(), outBitmap);
         return;
     }
     outBitmap->setInfo(info(), rowBytes());
     outBitmap->setPixelRef(this);
-    outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
 }
 
 void Bitmap::getSkBitmapForShaders(SkBitmap* outBitmap) {
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 2c48242..022e871 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -27,6 +27,8 @@
 #include "utils/Macros.h"
 #include "utils/TimeUtils.h"
 
+#include <ui/GraphicBuffer.h>
+
 namespace android {
 namespace uirenderer {
 namespace renderthread {
@@ -663,6 +665,18 @@
     return hardwareBitmap;
 }
 
+CREATE_BRIDGE3(copyGraphicBufferInto, RenderThread* thread, GraphicBuffer* buffer, SkBitmap* bitmap) {
+    return (void*) args->thread->readback().copyGraphicBufferInto(args->buffer, args->bitmap);
+}
+
+int RenderProxy::copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap) {
+    SETUP_TASK(copyGraphicBufferInto);
+    args->thread = &RenderThread::getInstance();
+    args->bitmap = bitmap;
+    args->buffer = buffer;
+    return static_cast<int>(reinterpret_cast<intptr_t>(staticPostAndWait(task)));
+}
+
 void RenderProxy::post(RenderTask* task) {
     mRenderThread.queue(task);
 }
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index e559142..44a5a14 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -35,6 +35,8 @@
 #include "DrawFrameTask.h"
 
 namespace android {
+class GraphicBuffer;
+
 namespace uirenderer {
 
 class DeferredLayerUpdater;
@@ -131,6 +133,8 @@
     ANDROID_API static void prepareToDraw(Bitmap& bitmap);
 
     static sk_sp<Bitmap> allocateHardwareBitmap(SkBitmap& bitmap);
+
+    static int copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap);
 private:
     RenderThread& mRenderThread;
     CanvasContext* mContext;
diff --git a/libs/hwui/tests/common/scenes/ReadbackFromHardwareBitmap.cpp b/libs/hwui/tests/common/scenes/ReadbackFromHardwareBitmap.cpp
new file mode 100644
index 0000000..bc6fc64
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/ReadbackFromHardwareBitmap.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 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 "TestSceneBase.h"
+
+class ReadbackFromHardware;
+
+static TestScene::Registrar _SaveLayer(TestScene::Info{
+    "readbackFromHBitmap",
+    "Allocates hardware bitmap and readback data from it.",
+    TestScene::simpleCreateScene<ReadbackFromHardware>
+});
+
+class ReadbackFromHardware : public TestScene {
+public:
+    static sk_sp<Bitmap> createHardwareBitmap() {
+        SkBitmap skBitmap;
+        SkImageInfo info = SkImageInfo::Make(400, 400, kN32_SkColorType, kPremul_SkAlphaType);
+        skBitmap.allocPixels(info);
+        skBitmap.eraseColor(Color::Red_500);
+        SkCanvas canvas(skBitmap);
+        SkPaint paint;
+        paint.setColor(Color::Blue_500);
+        canvas.drawRect(SkRect::MakeXYWH(30, 30, 30, 150), paint);
+        canvas.drawRect(SkRect::MakeXYWH(30, 30, 100, 30), paint);
+        canvas.drawRect(SkRect::MakeXYWH(30, 100, 70, 30), paint);
+        return Bitmap::allocateHardwareBitmap(skBitmap);
+    }
+
+    void createContent(int width, int height, Canvas& canvas) override {
+        canvas.drawColor(Color::White, SkBlendMode::kSrcOver); // background
+
+        sk_sp<Bitmap> hardwareBitmap(createHardwareBitmap());
+
+        SkBitmap readback;
+        hardwareBitmap->getSkBitmap(&readback);
+
+        SkBitmap canvasBitmap;
+        sk_sp<Bitmap> heapBitmap(TestUtils::createBitmap(hardwareBitmap->width(),
+                hardwareBitmap->height(), &canvasBitmap));
+
+        SkCanvas skCanvas(canvasBitmap);
+        skCanvas.drawBitmap(readback, 0, 0);
+        canvas.drawBitmap(*heapBitmap, 0, 0, nullptr);
+
+        canvas.drawBitmap(*hardwareBitmap, 0, 500, nullptr);
+    }
+
+    void doFrame(int frameNr) override { }
+};