Don't assume all FP16 bitmaps are linearly encoded.

The bitmap.create() function that does not take a colorspace does
not enforce that the bitmap is linearly encoded and as such it is
possible for us to end up with FP16 bitmaps that are sRGB encoded.

Given that we want to remove that restriction (see b/120870651)
we update getColorSpace to report the actual colorSpace of the
underlying bitmap. This pulls a thread that causes a chain of
updates to various classes to ensure proper handling of the native
colorspace.

Bug: 120904891
Test: CtsUiRenderingTestCases
Change-Id: I27780aa603138b0e48f9320c2837bc53e22cdf95
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index ad51c47..5de0883 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -19,6 +19,7 @@
 #include <hwui/Paint.h>
 #include <hwui/Bitmap.h>
 #include <renderthread/RenderProxy.h>
+#include <utils/Color.h>
 
 #include <android_runtime/android_hardware_HardwareBuffer.h>
 
@@ -602,6 +603,14 @@
     return static_cast<jint>(bitmap->getGenerationID());
 }
 
+static jboolean Bitmap_isConfigF16(JNIEnv* env, jobject, jlong bitmapHandle) {
+    LocalScopedBitmap bitmap(bitmapHandle);
+    if (bitmap->info().colorType() == kRGBA_F16_SkColorType) {
+        return JNI_TRUE;
+    }
+    return JNI_FALSE;
+}
+
 static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) {
     LocalScopedBitmap bitmap(bitmapHandle);
     if (bitmap->info().alphaType() == kPremul_SkAlphaType) {
@@ -1120,7 +1129,8 @@
     sp<GraphicBuffer> buffer(graphicBufferForJavaObject(env, graphicBuffer));
     // To support any color space, we need to pass an additional ColorSpace argument to
     // java Bitmap.createHardwareBitmap.
-    sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer, SkColorSpace::MakeSRGB());
+    SkColorType ct = uirenderer::PixelFormatToColorType(buffer->getPixelFormat());
+    sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer, ct, SkColorSpace::MakeSRGB());
     if (!bitmap.get()) {
         ALOGW("failed to create hardware bitmap from graphic buffer");
         return NULL;
@@ -1133,7 +1143,8 @@
     AHardwareBuffer* hwBuf = android_hardware_HardwareBuffer_getNativeHardwareBuffer(env,
         hardwareBuffer);
     sp<GraphicBuffer> buffer(AHardwareBuffer_to_GraphicBuffer(hwBuf));
-    sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer,
+    SkColorType ct = uirenderer::PixelFormatToColorType(buffer->getPixelFormat());
+    sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer, ct,
             GraphicsJNI::getNativeColorSpace(colorSpacePtr));
     if (!bitmap.get()) {
         ALOGW("failed to create hardware bitmap from hardware buffer");
@@ -1193,6 +1204,7 @@
     {   "nativeErase",              "(JJJ)V", (void*)Bitmap_eraseLong },
     {   "nativeRowBytes",           "(J)I", (void*)Bitmap_rowBytes },
     {   "nativeConfig",             "(J)I", (void*)Bitmap_config },
+    {   "nativeIsConfigF16",        "(J)Z", (void*)Bitmap_isConfigF16 },
     {   "nativeHasAlpha",           "(J)Z", (void*)Bitmap_hasAlpha },
     {   "nativeIsPremultiplied",    "(J)Z", (void*)Bitmap_isPremultiplied},
     {   "nativeSetHasAlpha",        "(JZZ)V", (void*)Bitmap_setHasAlpha},
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 5a8ab3c..32e6ac0 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -1011,8 +1011,9 @@
         // Continue I guess?
     }
 
+    SkColorType ct = uirenderer::PixelFormatToColorType(buffer->getPixelFormat());
     sk_sp<SkColorSpace> cs = uirenderer::DataSpaceToColorSpace(bufferItem.mDataSpace);
-    sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer, cs);
+    sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer, ct, cs);
     return bitmap::createBitmap(env, bitmap.release(),
             android::bitmap::kBitmapCreateFlag_Premultiplied);
 }
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index bfbdbc5..8636949 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -1711,20 +1711,22 @@
      */
     @Nullable
     public final ColorSpace getColorSpace() {
-        // A reconfigure can change the configuration and rgba16f is
-        // always linear scRGB at this time
-        if (getConfig() == Config.RGBA_F16) {
-            // Reset the color space for potential future reconfigurations
-            mColorSpace = null;
-            return ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB);
-        }
-
+        checkRecycled("getColorSpace called on a recycled bitmap");
         // Cache the color space retrieval since it can be fairly expensive
         if (mColorSpace == null) {
-            if (nativeIsSRGB(mNativePtr)) {
+            if (nativeIsConfigF16(mNativePtr)) {
+                // an F16 bitmaps is intended to always be linear extended, but due to
+                // inconsistencies in Bitmap.create() functions it is possible to have
+                // rendered into a bitmap in non-linear sRGB.
+                if (nativeIsSRGB(mNativePtr)) {
+                    mColorSpace = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB);
+                } else {
+                    mColorSpace = ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB);
+                }
+            } else if (nativeIsSRGB(mNativePtr)) {
                 mColorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
-            } else if (getConfig() == Config.HARDWARE && nativeIsSRGBLinear(mNativePtr)) {
-                mColorSpace = ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB);
+            } else if (nativeIsSRGBLinear(mNativePtr)) {
+                mColorSpace = ColorSpace.get(ColorSpace.Named.LINEAR_SRGB);
             } else {
                 float[] xyz = new float[9];
                 float[] params = new float[7];
@@ -2127,6 +2129,7 @@
     private static native void nativeErase(long nativeBitmap, long colorSpacePtr, long color);
     private static native int nativeRowBytes(long nativeBitmap);
     private static native int nativeConfig(long nativeBitmap);
+    private static native boolean nativeIsConfigF16(long nativeBitmap);
 
     private static native int nativeGetPixel(long nativeBitmap, int x, int y);
     private static native void nativeGetPixels(long nativeBitmap, int[] pixels,
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index 635d0ec..39bfcdd 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -164,15 +164,11 @@
         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
-            source.readPixels(bitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()),
-                              bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
-        } else {
-            SkCanvas canvas(bitmap);
-            canvas.drawBitmap(source, 0.0f, 0.0f, nullptr);
-        }
+
+        SkCanvas canvas(bitmap);
+        canvas.drawColor(0);
+        canvas.drawBitmap(source, 0.0f, 0.0f, nullptr);
+
         return bitmap;
     }
 }
@@ -253,8 +249,8 @@
         eglDestroySyncKHR(display, fence);
     }
 
-    return Bitmap::createFrom(buffer.get(), bitmap.refColorSpace(), bitmap.alphaType(),
-                              Bitmap::computePalette(bitmap));
+    return Bitmap::createFrom(buffer.get(), bitmap.colorType(), bitmap.refColorSpace(),
+                              bitmap.alphaType(), Bitmap::computePalette(bitmap));
 }
 
 void HardwareBitmapUploader::terminate() {
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 6e0258c..3bbee18 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -133,12 +133,11 @@
 }
 
 
-sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer, sk_sp<SkColorSpace> colorSpace,
-                                 SkAlphaType alphaType, BitmapPalette palette) {
-    // As we will be effectively texture-sampling the buffer (using either EGL or Vulkan), we can
-    // view the format as RGBA8888.
+sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer, SkColorType colorType,
+                                 sk_sp<SkColorSpace> colorSpace, SkAlphaType alphaType,
+                                 BitmapPalette palette) {
     SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(),
-                                         kRGBA_8888_SkColorType, alphaType, colorSpace);
+                                         colorType, alphaType, colorSpace);
     return sk_sp<Bitmap>(new Bitmap(graphicBuffer.get(), info, palette));
 }
 
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index 2138040..01e4516 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -72,6 +72,7 @@
      * memory that is provided as an input param.
      */
     static sk_sp<Bitmap> createFrom(sp<GraphicBuffer> graphicBuffer,
+                                    SkColorType colorType,
                                     sk_sp<SkColorSpace> colorSpace,
                                     SkAlphaType alphaType = kPremul_SkAlphaType,
                                     BitmapPalette palette = BitmapPalette::Unknown);
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 53495a7..20fbab3 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -149,20 +149,8 @@
 
 sk_sp<Bitmap> SkiaVulkanPipeline::allocateHardwareBitmap(renderthread::RenderThread& renderThread,
                                                          SkBitmap& skBitmap) {
-    // TODO: implement this function for Vulkan pipeline
-    // code below is a hack to avoid crashing because of missing HW Bitmap support
-    sp<GraphicBuffer> buffer = new GraphicBuffer(
-            skBitmap.info().width(), skBitmap.info().height(), PIXEL_FORMAT_RGBA_8888,
-            GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER |
-                    GraphicBuffer::USAGE_SW_READ_NEVER,
-            std::string("SkiaVulkanPipeline::allocateHardwareBitmap pid [") +
-                    std::to_string(getpid()) + "]");
-    status_t error = buffer->initCheck();
-    if (error < 0) {
-        ALOGW("SkiaVulkanPipeline::allocateHardwareBitmap() failed in GraphicBuffer.create()");
-        return nullptr;
-    }
-    return Bitmap::createFrom(buffer, skBitmap.refColorSpace());
+    LOG_ALWAYS_FATAL("Unimplemented");
+    return nullptr;
 }
 
 } /* namespace skiapipeline */
diff --git a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
index ec81f62..2af955f 100644
--- a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
+++ b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
@@ -50,7 +50,8 @@
             pixels[4000 + 4 * i + 3] = 255;
         }
         buffer->unlock();
-        sk_sp<Bitmap> hardwareBitmap(Bitmap::createFrom(buffer, SkColorSpace::MakeSRGB()));
+        sk_sp<Bitmap> hardwareBitmap(Bitmap::createFrom(buffer, kRGBA_8888_SkColorType,
+                                                        SkColorSpace::MakeSRGB()));
         sk_sp<SkShader> hardwareShader(createBitmapShader(*hardwareBitmap));
 
         SkPoint center;
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index 4415a59..d14116f 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -45,6 +45,20 @@
     }
 }
 
+SkColorType PixelFormatToColorType(android::PixelFormat format) {
+    switch (format) {
+        case PIXEL_FORMAT_RGBX_8888:    return kRGB_888x_SkColorType;
+        case PIXEL_FORMAT_RGBA_8888:    return kRGBA_8888_SkColorType;
+        case PIXEL_FORMAT_RGBA_FP16:    return kRGBA_F16_SkColorType;
+        case PIXEL_FORMAT_RGB_565:      return kRGB_565_SkColorType;
+        case PIXEL_FORMAT_RGBA_1010102: return kRGBA_1010102_SkColorType;
+        case PIXEL_FORMAT_RGBA_4444:    return kARGB_4444_SkColorType;
+        default:
+            ALOGW("Unsupported PixelFormat: %d, return kUnknown_SkColorType by default", format);
+            return kUnknown_SkColorType;
+    }
+}
+
 sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) {
 
     skcms_Matrix3x3 gamut;
diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h
index 3880252..b67d10d 100644
--- a/libs/hwui/utils/Color.h
+++ b/libs/hwui/utils/Color.h
@@ -112,6 +112,7 @@
 }
 
 android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType);
+ANDROID_API SkColorType PixelFormatToColorType(android::PixelFormat format);
 
 ANDROID_API sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace);