Move all non-GL HW Bitmap work off RT

Bug: 78288006
Test: hwuiunit passes, systrace showed work distribution as expected,
and photos using HW bitmaps still works

Change-Id: Id3285b637b5d74d3c5891ed3051ac1e44015987a
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index c3357a2..5b2adbf 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -222,24 +222,6 @@
 
 #define FENCE_TIMEOUT 2000000000
 
-class AutoEglFence {
-public:
-    AutoEglFence(EGLDisplay display) : mDisplay(display) {
-        fence = eglCreateSyncKHR(mDisplay, EGL_SYNC_FENCE_KHR, NULL);
-    }
-
-    ~AutoEglFence() {
-        if (fence != EGL_NO_SYNC_KHR) {
-            eglDestroySyncKHR(mDisplay, fence);
-        }
-    }
-
-    EGLSyncKHR fence = EGL_NO_SYNC_KHR;
-
-private:
-    EGLDisplay mDisplay = EGL_NO_DISPLAY;
-};
-
 class AutoEglImage {
 public:
     AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer) : mDisplay(display) {
@@ -273,73 +255,102 @@
     GLuint mTexture = 0;
 };
 
-sk_sp<Bitmap> SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThread& renderThread,
-                                                         SkBitmap& skBitmap) {
-    renderThread.requireGlContext();
+struct FormatInfo {
 
-    sk_sp<GrContext> grContext = sk_ref_sp(renderThread.getGrContext());
-    const SkImageInfo& info = skBitmap.info();
     PixelFormat pixelFormat;
     GLint format, type;
     bool isSupported = false;
+    bool valid = true;
+};
 
+static bool gpuSupportsHalfFloatTextures(renderthread::RenderThread& renderThread) {
+    static bool isSupported = renderThread.queue().runSync([&renderThread]() -> bool {
+        renderThread.requireGlContext();
+        sk_sp<GrContext> grContext = sk_ref_sp(renderThread.getGrContext());
+        return grContext->colorTypeSupportedAsImage(kRGBA_F16_SkColorType);
+    });
+    return isSupported;
+}
+
+static FormatInfo determineFormat(renderthread::RenderThread& renderThread,
+                                  const SkBitmap& skBitmap) {
+    FormatInfo formatInfo;
     // TODO: add support for linear blending (when ANDROID_ENABLE_LINEAR_BLENDING is defined)
-    switch (info.colorType()) {
+    switch (skBitmap.info().colorType()) {
         case kRGBA_8888_SkColorType:
-            isSupported = true;
+            formatInfo.isSupported = true;
         // ARGB_4444 is upconverted to RGBA_8888
         case kARGB_4444_SkColorType:
-            pixelFormat = PIXEL_FORMAT_RGBA_8888;
-            format = GL_RGBA;
-            type = GL_UNSIGNED_BYTE;
+            formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888;
+            formatInfo.format = GL_RGBA;
+            formatInfo.type = GL_UNSIGNED_BYTE;
             break;
         case kRGBA_F16_SkColorType:
-            isSupported = grContext->colorTypeSupportedAsImage(kRGBA_F16_SkColorType);
-            if (isSupported) {
-                type = GL_HALF_FLOAT;
-                pixelFormat = PIXEL_FORMAT_RGBA_FP16;
+            formatInfo.isSupported = gpuSupportsHalfFloatTextures(renderThread);
+            if (formatInfo.isSupported) {
+                formatInfo.type = GL_HALF_FLOAT;
+                formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_FP16;
             } else {
-                type = GL_UNSIGNED_BYTE;
-                pixelFormat = PIXEL_FORMAT_RGBA_8888;
+                formatInfo.type = GL_UNSIGNED_BYTE;
+                formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888;
             }
-            format = GL_RGBA;
+            formatInfo.format = GL_RGBA;
             break;
         case kRGB_565_SkColorType:
-            isSupported = true;
-            pixelFormat = PIXEL_FORMAT_RGB_565;
-            format = GL_RGB;
-            type = GL_UNSIGNED_SHORT_5_6_5;
+            formatInfo.isSupported = true;
+            formatInfo.pixelFormat = PIXEL_FORMAT_RGB_565;
+            formatInfo.format = GL_RGB;
+            formatInfo.type = GL_UNSIGNED_SHORT_5_6_5;
             break;
         case kGray_8_SkColorType:
-            isSupported = true;
-            pixelFormat = PIXEL_FORMAT_RGBA_8888;
-            format = GL_LUMINANCE;
-            type = GL_UNSIGNED_BYTE;
+            formatInfo.isSupported = true;
+            formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888;
+            formatInfo.format = GL_LUMINANCE;
+            formatInfo.type = GL_UNSIGNED_BYTE;
             break;
         default:
-            ALOGW("unable to create hardware bitmap of colortype: %d", info.colorType());
-            return nullptr;
+            ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType());
+            formatInfo.valid = false;
     }
+    return formatInfo;
+}
 
-    SkBitmap bitmap;
-    if (isSupported) {
-        bitmap = skBitmap;
+static SkBitmap makeHwCompatible(const FormatInfo& format, const SkBitmap& source) {
+    if (format.isSupported) {
+        return source;
     } else {
+        SkBitmap bitmap;
+        const SkImageInfo& info = source.info();
         bitmap.allocPixels(
                 SkImageInfo::MakeN32(info.width(), info.height(), info.alphaType(), nullptr));
         bitmap.eraseColor(0);
         if (info.colorType() == kRGBA_F16_SkColorType) {
             // Drawing RGBA_F16 onto ARGB_8888 is not supported
-            skBitmap.readPixels(bitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()),
-                                bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
+            source.readPixels(bitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()),
+                              bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
         } else {
             SkCanvas canvas(bitmap);
-            canvas.drawBitmap(skBitmap, 0.0f, 0.0f, nullptr);
+            canvas.drawBitmap(source, 0.0f, 0.0f, nullptr);
         }
+        return bitmap;
+    }
+}
+
+sk_sp<Bitmap> SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThread& thread,
+                                                         const SkBitmap& sourceBitmap) {
+    ATRACE_CALL();
+
+    LOG_ALWAYS_FATAL_IF(thread.isCurrent(), "Must not be called on RenderThread");
+
+    FormatInfo format = determineFormat(thread, sourceBitmap);
+    if (!format.valid) {
+        return nullptr;
     }
 
+    SkBitmap bitmap = makeHwCompatible(format, sourceBitmap);
     sp<GraphicBuffer> buffer = new GraphicBuffer(
-            info.width(), info.height(), pixelFormat,
+            static_cast<uint32_t>(bitmap.width()), static_cast<uint32_t>(bitmap.height()),
+            format.pixelFormat,
             GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER |
                     GraphicBuffer::USAGE_SW_READ_NEVER,
             std::string("Bitmap::allocateSkiaHardwareBitmap pid [") + std::to_string(getpid()) +
@@ -351,8 +362,11 @@
         return nullptr;
     }
 
-    // upload the bitmap into a texture
-    EGLDisplay display = eglGetCurrentDisplay();
+    EGLDisplay display = thread.queue().runSync([&]() -> EGLDisplay {
+        thread.requireGlContext();
+        return eglGetCurrentDisplay();
+    });
+
     LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
                         uirenderer::renderthread::EglManager::eglErrorString());
     // We use an EGLImage to access the content of the GraphicBuffer
@@ -364,35 +378,40 @@
               uirenderer::renderthread::EglManager::eglErrorString());
         return nullptr;
     }
-    AutoSkiaGlTexture glTexture;
-    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
-    GL_CHECKPOINT(MODERATE);
 
-    // glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we provide.
-    // But asynchronous in sense that driver may upload texture onto hardware buffer when we first
-    // use it in drawing
-    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, info.width(), info.height(), format, type,
-                    bitmap.getPixels());
-    GL_CHECKPOINT(MODERATE);
+    {
+        ATRACE_FORMAT("CPU -> gralloc transfer (%dx%d)", bitmap.width(), bitmap.height());
+        EGLSyncKHR fence = thread.queue().runSync([&]() -> EGLSyncKHR {
+            thread.requireGlContext();
+            sk_sp<GrContext> grContext = sk_ref_sp(thread.getGrContext());
+            AutoSkiaGlTexture glTexture;
+            glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
+            GL_CHECKPOINT(MODERATE);
 
-    // The fence is used to wait for the texture upload to finish
-    // properly. We cannot rely on glFlush() and glFinish() as
-    // some drivers completely ignore these API calls
-    AutoEglFence autoFence(display);
-    if (autoFence.fence == EGL_NO_SYNC_KHR) {
-        LOG_ALWAYS_FATAL("Could not create sync fence %#x", eglGetError());
-        return nullptr;
+            // glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we
+            // provide.
+            // But asynchronous in sense that driver may upload texture onto hardware buffer when we
+            // first
+            // use it in drawing
+            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(), format.format,
+                            format.type, bitmap.getPixels());
+            GL_CHECKPOINT(MODERATE);
+
+            EGLSyncKHR uploadFence =
+                    eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL);
+            LOG_ALWAYS_FATAL_IF(uploadFence == EGL_NO_SYNC_KHR, "Could not create sync fence %#x",
+                                eglGetError());
+            glFlush();
+            grContext->resetContext(kTextureBinding_GrGLBackendState);
+            return uploadFence;
+        });
+
+        EGLint waitStatus = eglClientWaitSyncKHR(display, fence, 0, FENCE_TIMEOUT);
+        LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR,
+                            "Failed to wait for the fence %#x", eglGetError());
+
+        eglDestroySyncKHR(display, fence);
     }
-    // The flag EGL_SYNC_FLUSH_COMMANDS_BIT_KHR will trigger a
-    // pipeline flush (similar to what a glFlush() would do.)
-    EGLint waitStatus = eglClientWaitSyncKHR(display, autoFence.fence,
-                                             EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT);
-    if (waitStatus != EGL_CONDITION_SATISFIED_KHR) {
-        LOG_ALWAYS_FATAL("Failed to wait for the fence %#x", eglGetError());
-        return nullptr;
-    }
-
-    grContext->resetContext(kTextureBinding_GrGLBackendState);
 
     return sk_sp<Bitmap>(new Bitmap(buffer.get(), bitmap.info()));
 }
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index 5e013b6..ef5d934 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -49,8 +49,10 @@
     bool isContextReady() override;
 
     static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
+
+    // May be called by any thread except RenderThread.
     static sk_sp<Bitmap> allocateHardwareBitmap(renderthread::RenderThread& thread,
-                                                SkBitmap& skBitmap);
+                                                const SkBitmap& skBitmap);
 
 private:
     renderthread::EglManager& mEglManager;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 4b948f8..0caf59b 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -21,6 +21,7 @@
 #include "Properties.h"
 #include "Readback.h"
 #include "Rect.h"
+#include "pipeline/skia/SkiaOpenGLPipeline.h"
 #include "pipeline/skia/VectorDrawableAtlas.h"
 #include "renderstate/RenderState.h"
 #include "renderthread/CanvasContext.h"
@@ -323,7 +324,13 @@
 
 sk_sp<Bitmap> RenderProxy::allocateHardwareBitmap(SkBitmap& bitmap) {
     auto& thread = RenderThread::getInstance();
-    return thread.queue().runSync([&]() -> auto { return thread.allocateHardwareBitmap(bitmap); });
+    if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
+        return skiapipeline::SkiaOpenGLPipeline::allocateHardwareBitmap(thread, bitmap);
+    } else {
+        return thread.queue().runSync([&]() -> auto {
+            return thread.allocateHardwareBitmap(bitmap);
+        });
+    }
 }
 
 int RenderProxy::copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap) {
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 711ece4..5dcfc3f 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -24,8 +24,8 @@
 #include "hwui/Bitmap.h"
 #include "pipeline/skia/SkiaOpenGLPipeline.h"
 #include "pipeline/skia/SkiaOpenGLReadback.h"
-#include "pipeline/skia/SkiaVulkanReadback.h"
 #include "pipeline/skia/SkiaVulkanPipeline.h"
+#include "pipeline/skia/SkiaVulkanReadback.h"
 #include "renderstate/RenderState.h"
 #include "utils/FatVector.h"
 #include "utils/TimeUtils.h"
@@ -98,14 +98,11 @@
     DummyVsyncSource(RenderThread* renderThread) : mRenderThread(renderThread) {}
 
     virtual void requestNextVsync() override {
-        mRenderThread->queue().postDelayed(16_ms, [this]() {
-            mRenderThread->drainDisplayEventQueue();
-        });
+        mRenderThread->queue().postDelayed(16_ms,
+                                           [this]() { mRenderThread->drainDisplayEventQueue(); });
     }
 
-    virtual nsecs_t latestVsyncEvent() override {
-        return systemTime(CLOCK_MONOTONIC);
-    }
+    virtual nsecs_t latestVsyncEvent() override { return systemTime(CLOCK_MONOTONIC); }
 
 private:
     RenderThread* mRenderThread;
@@ -152,13 +149,13 @@
         auto receiver = std::make_unique<DisplayEventReceiver>();
         status_t status = receiver->initCheck();
         LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
-                "Initialization of DisplayEventReceiver "
-                        "failed with status: %d",
-                status);
+                            "Initialization of DisplayEventReceiver "
+                            "failed with status: %d",
+                            status);
 
         // Register the FD
         mLooper->addFd(receiver->getFd(), 0, Looper::EVENT_INPUT,
-                RenderThread::displayEventReceiverCallback, this);
+                       RenderThread::displayEventReceiverCallback, this);
         mVsyncSource = new DisplayEventReceiverWrapper(std::move(receiver));
     } else {
         mVsyncSource = new DummyVsyncSource(this);
@@ -372,8 +369,6 @@
 sk_sp<Bitmap> RenderThread::allocateHardwareBitmap(SkBitmap& skBitmap) {
     auto renderType = Properties::getRenderPipelineType();
     switch (renderType) {
-        case RenderPipelineType::SkiaGL:
-            return skiapipeline::SkiaOpenGLPipeline::allocateHardwareBitmap(*this, skBitmap);
         case RenderPipelineType::SkiaVulkan:
             return skiapipeline::SkiaVulkanPipeline::allocateHardwareBitmap(*this, skBitmap);
         default: