Fix recent apps in system UI for Skia pipeline

Enable HW Bitmaps for Skia pipeline just enough to make
recent apps list working by adding support for BitmapShader.
Drawing HW bitmaps in a canvas is also supported.

Test: recent apps work, HWUI unit tests pass, CTS tests pass.
bug: 38136140
Change-Id: Ibd06c859c86dc213310d5ce5272497e1882d0cc6
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index 214d97c..b529e37 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -60,14 +60,17 @@
 static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jobject jbitmap,
         jint tileModeX, jint tileModeY) {
     const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
-    SkBitmap bitmap;
+    sk_sp<SkImage> image;
     if (jbitmap) {
         // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
         // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
-        android::bitmap::toBitmap(env, jbitmap).getSkBitmapForShaders(&bitmap);
+        image = android::bitmap::toBitmap(env, jbitmap).makeImage(nullptr);
     }
 
-    sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
+    if (!image.get()) {
+        SkBitmap bitmap;
+        image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
+    }
     sk_sp<SkShader> baseShader = image->makeShader(
             (SkShader::TileMode)tileModeX, (SkShader::TileMode)tileModeY);
 
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index d8207b1..959b28b 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -16,6 +16,7 @@
 #include "Bitmap.h"
 
 #include "Caches.h"
+#include "pipeline/skia/SkiaOpenGLPipeline.h"
 #include "renderthread/EglManager.h"
 #include "renderthread/RenderThread.h"
 #include "renderthread/RenderProxy.h"
@@ -34,11 +35,15 @@
 #include <private/gui/ComposerService.h>
 #include <binder/IServiceManager.h>
 #include <ui/PixelFormat.h>
+#include <GrTexture.h>
 
 #include <SkCanvas.h>
+#include <SkImagePriv.h>
 
 namespace android {
 
+Mutex Bitmap::gLock;
+
 static bool computeAllocationSize(size_t rowBytes, int height, size_t* size) {
     int32_t rowBytes32 = SkToS32(rowBytes);
     int64_t bigSize = (int64_t) height * rowBytes32;
@@ -311,8 +316,7 @@
         return nullptr;
     }
     SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(),
-            kRGBA_8888_SkColorType, kPremul_SkAlphaType,
-            SkColorSpace::MakeSRGB());
+            kRGBA_8888_SkColorType, kPremul_SkAlphaType, SkColorSpace::MakeSRGB());
     return sk_sp<Bitmap>(new Bitmap(graphicBuffer.get(), info));
 }
 
@@ -392,6 +396,7 @@
         , mPixelStorageType(PixelStorageType::Hardware) {
     mPixelStorage.hardware.buffer = buffer;
     buffer->incStrong(buffer);
+    setImmutable(); // HW bitmaps are always immutable
 }
 
 Bitmap::~Bitmap() {
@@ -474,7 +479,13 @@
 void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
     outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
     if (isHardware()) {
-        outBitmap->allocPixels(info());
+        if (uirenderer::Properties::isSkiaEnabled()) {
+            // TODO: add color correctness for Skia pipeline - pass null color space for now
+            outBitmap->allocPixels(SkImageInfo::Make(info().width(), info().height(),
+                    info().colorType(), info().alphaType(), nullptr));
+        } else {
+            outBitmap->allocPixels(info());
+        }
         uirenderer::renderthread::RenderProxy::copyGraphicBufferInto(graphicBuffer(), outBitmap);
         return;
     }
@@ -500,4 +511,28 @@
     return nullptr;
 }
 
+sk_sp<SkImage> Bitmap::makeImage(const uirenderer::renderthread::RenderThread* renderThread) {
+    AutoMutex _lock(gLock); //TODO: implement lock free solution
+    auto image = mImage;
+    //TODO: use new API SkImage::isValid() instead of SkImage::getTexture()->getContext()
+    if (!image.get() || (image->getTexture() && nullptr == image->getTexture()->getContext())) {
+        if (isHardware() && uirenderer::RenderPipelineType::SkiaGL
+                == uirenderer::Properties::getRenderPipelineType()) {
+            //TODO: add Vulkan support
+            if (renderThread) {
+                image = uirenderer::skiapipeline::SkiaOpenGLPipeline::makeTextureImage(
+                        *renderThread, this);
+            } else {
+                image = uirenderer::renderthread::RenderProxy::makeTextureImage(this);
+            }
+        } else {
+            SkBitmap skiaBitmap;
+            getSkBitmapForShaders(&skiaBitmap);
+            image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
+        }
+        mImage = image;
+    }
+    return image;
+}
+
 } // namespace android
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index 9a76715..e650c20 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -22,6 +22,8 @@
 #include <SkPixelRef.h>
 #include <cutils/compiler.h>
 #include <ui/GraphicBuffer.h>
+#include <utils/Mutex.h>
+#include <SkImage.h>
 
 namespace android {
 
@@ -105,6 +107,13 @@
     }
 
     GraphicBuffer* graphicBuffer();
+
+    // makeImage creates or returns a cached SkImage. Can be invoked from UI or render thread.
+    // If invoked on the render thread, then RenderThread* argument is required.
+    // If not invoked on the render thread, then RenderThread* must be nullptr.
+    // makeImage is wrapping a gralloc buffer with an EGLImage and is passing a texture to Skia.
+    // This is a temporary implementation until Skia can wrap the gralloc buffer in a SkImage.
+    sk_sp<SkImage> makeImage(const uirenderer::renderthread::RenderThread*);
 private:
     Bitmap(GraphicBuffer* buffer, const SkImageInfo& info);
     virtual ~Bitmap();
@@ -135,6 +144,9 @@
             GraphicBuffer* buffer;
         } hardware;
     } mPixelStorage;
+
+    sk_sp<SkImage> mImage;
+    static Mutex gLock;
 };
 
 } //namespace android
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index ae13131..4885873 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -28,6 +28,8 @@
 
 #include <cutils/properties.h>
 #include <strings.h>
+#include <SkImagePriv.h>
+#include <gl/GrGLTypes.h>
 
 using namespace android::uirenderer::renderthread;
 
@@ -197,6 +199,87 @@
     }
 }
 
+static void deleteImageTexture(void* context) {
+     EGLImageKHR EGLimage = reinterpret_cast<EGLImageKHR>(context);
+     if (EGLimage != EGL_NO_IMAGE_KHR) {
+        EGLDisplay display = eglGetCurrentDisplay();
+        if (EGL_NO_DISPLAY == display) {
+            display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+        }
+        eglDestroyImageKHR(display, EGLimage);
+     }
+}
+
+sk_sp<SkImage> SkiaOpenGLPipeline::makeTextureImage(
+        const uirenderer::renderthread::RenderThread& renderThread, Bitmap* bitmap) {
+    renderThread.eglManager().initialize();
+
+    GraphicBuffer* buffer = bitmap->graphicBuffer();
+    EGLDisplay display = eglGetCurrentDisplay();
+    if (EGL_NO_DISPLAY == display) {
+        display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    }
+    LOG_ALWAYS_FATAL_IF(!bitmap->isHardware(),
+                "Texture image requires a HW bitmap.");
+    // We use an EGLImage to access the content of the GraphicBuffer
+    // The EGL image is later bound to a 2D texture
+    EGLClientBuffer clientBuffer = (EGLClientBuffer) buffer->getNativeBuffer();
+    EGLint imageAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
+    EGLImageKHR EGLimage = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+            clientBuffer, imageAttrs);
+    if (EGLimage == EGL_NO_IMAGE_KHR) {
+        ALOGW("Could not create EGL image, err =%s",
+                uirenderer::renderthread::EglManager::eglErrorString());
+        return nullptr;
+    }
+
+    GLuint textureId = 0;
+    glGenTextures(1, &textureId);
+    glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId);
+    glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, EGLimage);
+
+    GLenum status = GL_NO_ERROR;
+    while ((status = glGetError()) != GL_NO_ERROR) {
+        ALOGW("glEGLImageTargetTexture2DOES failed (%#x)", status);
+        eglDestroyImageKHR(display, EGLimage);
+        return nullptr;
+    }
+
+    sk_sp<GrContext> grContext = sk_ref_sp(renderThread.getGrContext());
+    grContext->resetContext();
+
+    GrGLTextureInfo textureInfo;
+    textureInfo.fTarget = GL_TEXTURE_EXTERNAL_OES;
+    textureInfo.fID = textureId;
+
+    GrBackendTextureDesc textureDescription;
+    textureDescription.fWidth = bitmap->info().width();
+    textureDescription.fHeight = bitmap->info().height();
+    textureDescription.fOrigin = kTopLeft_GrSurfaceOrigin;
+    textureDescription.fTextureHandle = reinterpret_cast<GrBackendObject>(&textureInfo);
+    PixelFormat format = buffer->getPixelFormat();
+    switch (format) {
+    case PIXEL_FORMAT_RGBA_8888:
+        textureDescription.fConfig = kRGBA_8888_GrPixelConfig;
+        break;
+    case PIXEL_FORMAT_RGBA_FP16:
+        textureDescription.fConfig = kRGBA_half_GrPixelConfig;
+        break;
+    default:
+        eglDestroyImageKHR(display, EGLimage);
+        return nullptr;
+    }
+
+    // TODO: add color correctness - pass null color space for now
+    sk_sp<SkImage> image = SkImage::MakeFromTexture(grContext.get(), textureDescription,
+                bitmap->info().alphaType(), nullptr, deleteImageTexture, EGLimage);
+    if (!image.get()) {
+        eglDestroyImageKHR(display, EGLimage);
+        return nullptr;
+    }
+    return image;
+}
+
 } /* namespace skiapipeline */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index 36685dd..f3ce189 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -46,6 +46,8 @@
     bool isContextReady() override;
 
     static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
+    static sk_sp<SkImage> makeTextureImage(
+            const uirenderer::renderthread::RenderThread& renderThread, Bitmap* bitmap);
 
 private:
     renderthread::EglManager& mEglManager;
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
index 04aeb7c..1863bdc 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
@@ -61,6 +61,7 @@
     textureDescription.fTextureHandle = reinterpret_cast<GrBackendObject>(&externalTexture);
 
     CopyResult copyResult = CopyResult::UnknownError;
+    // TODO: add color correctness - pass null color space for now
     sk_sp<SkImage> image(SkImage::MakeFromAdoptedTexture(grContext.get(), textureDescription));
     if (image) {
         // convert to Skia data structures
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 75f1adc..75fb070 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -159,11 +159,11 @@
     GrContext* context = thread.getGrContext();
     if (context) {
         ATRACE_FORMAT("Bitmap#prepareToDraw %dx%d", bitmap->width(), bitmap->height());
-        SkBitmap skiaBitmap;
-        bitmap->getSkBitmap(&skiaBitmap);
-        sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
-        SkImage_pinAsTexture(image.get(), context);
-        SkImage_unpinAsTexture(image.get(), context);
+        auto image = bitmap->makeImage(&thread);
+        if (image.get() && !bitmap->isHardware()) {
+            SkImage_pinAsTexture(image.get(), context);
+            SkImage_unpinAsTexture(image.get(), context);
+        }
     }
 }
 
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index b3173f2..d78bca9 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -156,11 +156,8 @@
 }
 
 void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
-    SkBitmap skBitmap;
-    bitmap.getSkBitmap(&skBitmap);
-
-    sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(skBitmap, kNever_SkCopyPixelsMode);
-    if (!skBitmap.isImmutable()) {
+    sk_sp<SkImage> image = bitmap.makeImage(nullptr);
+    if (!bitmap.isImmutable()) {
         mDisplayList->mMutableImages.push_back(image.get());
     }
     SkPaint tmpPaint;
@@ -169,12 +166,10 @@
 
 void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, const SkMatrix& matrix,
         const SkPaint* paint) {
-    SkBitmap bitmap;
-    hwuiBitmap.getSkBitmap(&bitmap);
     SkAutoCanvasRestore acr(&mRecorder, true);
     concat(matrix);
-    sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
-    if (!bitmap.isImmutable()) {
+    sk_sp<SkImage> image = hwuiBitmap.makeImage(nullptr);
+    if (!hwuiBitmap.isImmutable()) {
         mDisplayList->mMutableImages.push_back(image.get());
     }
     SkPaint tmpPaint;
@@ -184,12 +179,10 @@
 void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, float srcLeft, float srcTop,
         float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight,
         float dstBottom, const SkPaint* paint) {
-    SkBitmap bitmap;
-    hwuiBitmap.getSkBitmap(&bitmap);
     SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
     SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
-    sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
-    if (!bitmap.isImmutable()) {
+    sk_sp<SkImage> image = hwuiBitmap.makeImage(nullptr);
+    if (!hwuiBitmap.isImmutable()) {
         mDisplayList->mMutableImages.push_back(image.get());
     }
     SkPaint tmpPaint;
@@ -198,11 +191,8 @@
 
 void SkiaRecordingCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch& chunk,
         float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) {
-    SkBitmap bitmap;
-    hwuiBitmap.getSkBitmap(&bitmap);
-
     SkCanvas::Lattice lattice;
-    NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
+    NinePatchUtils::SetLatticeDivs(&lattice, chunk, hwuiBitmap.width(), hwuiBitmap.height());
 
     lattice.fFlags = nullptr;
     int numFlags = 0;
@@ -219,8 +209,8 @@
 
     lattice.fBounds = nullptr;
     SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
-    sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
-    if (!bitmap.isImmutable()) {
+    sk_sp<SkImage> image = hwuiBitmap.makeImage(nullptr);
+    if (!hwuiBitmap.isImmutable()) {
         mDisplayList->mMutableImages.push_back(image.get());
     }
 
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index a1f1717..5c2ec0e 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -693,6 +693,18 @@
     }
 }
 
+CREATE_BRIDGE2(makeTextureImage, RenderThread* thread, Bitmap* bitmap) {
+    return args->thread->makeTextureImage(args->bitmap).release();
+}
+
+sk_sp<SkImage> RenderProxy::makeTextureImage(Bitmap* bitmap) {
+    SETUP_TASK(makeTextureImage);
+    args->bitmap = bitmap;
+    args->thread = &RenderThread::getInstance();
+    sk_sp<SkImage> hardwareImage(reinterpret_cast<SkImage*>(staticPostAndWait(task)));
+    return hardwareImage;
+}
+
 void RenderProxy::post(RenderTask* task) {
     mRenderThread.queue(task);
 }
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index a60ed55..97ad796 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -135,6 +135,8 @@
     static sk_sp<Bitmap> allocateHardwareBitmap(SkBitmap& bitmap);
 
     static int copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap);
+
+    static sk_sp<SkImage> makeTextureImage(Bitmap* bitmap);
 private:
     RenderThread& mRenderThread;
     CanvasContext* mContext;
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 1450ec9..d62b556 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -17,6 +17,7 @@
 #include "RenderThread.h"
 
 #include "../renderstate/RenderState.h"
+#include "../pipeline/skia/SkiaOpenGLPipeline.h"
 #include "../pipeline/skia/SkiaOpenGLReadback.h"
 #include "CanvasContext.h"
 #include "EglManager.h"
@@ -433,6 +434,24 @@
     return next;
 }
 
+sk_sp<SkImage> RenderThread::makeTextureImage(Bitmap* bitmap) {
+    auto renderType = Properties::getRenderPipelineType();
+    sk_sp<SkImage> hardwareImage;
+    switch (renderType) {
+        case RenderPipelineType::SkiaGL:
+            hardwareImage = skiapipeline::SkiaOpenGLPipeline::makeTextureImage(*this, bitmap);
+            break;
+        case RenderPipelineType::SkiaVulkan:
+            //TODO: add Vulkan support
+            break;
+        default:
+            LOG_ALWAYS_FATAL("makeTextureImage: canvas context type %d not supported",
+                    (int32_t) renderType);
+            break;
+    }
+    return hardwareImage;
+}
+
 } /* namespace renderthread */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 9bc5985..34542c6 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -33,6 +33,7 @@
 
 namespace android {
 
+class Bitmap;
 class DisplayEventReceiver;
 
 namespace uirenderer {
@@ -104,6 +105,8 @@
 
     VulkanManager& vulkanManager() { return *mVkManager; }
 
+    sk_sp<SkImage> makeTextureImage(Bitmap* bitmap);
+
 protected:
     virtual bool threadLoop() override;