Add Gainmap bitmap & imagedecoder
Bug: 266628247
Test: builds & boots
Change-Id: I0da44e0c48cf8a6b6f95e3b62f6d5f74bd6c1eab
diff --git a/libs/hwui/jni/Bitmap.cpp b/libs/hwui/jni/Bitmap.cpp
old mode 100755
new mode 100644
index c68a6b9..10c287d
--- a/libs/hwui/jni/Bitmap.cpp
+++ b/libs/hwui/jni/Bitmap.cpp
@@ -6,6 +6,7 @@
#include <hwui/Paint.h>
#include "CreateJavaOutputStreamAdaptor.h"
+#include "Gainmap.h"
#include "GraphicsJNI.h"
#include "HardwareBufferHelpers.h"
#include "SkBitmap.h"
@@ -47,6 +48,8 @@
namespace android {
+jobject Gainmap_extractFromBitmap(JNIEnv* env, const Bitmap& bitmap);
+
class BitmapWrapper {
public:
explicit BitmapWrapper(Bitmap* bitmap)
@@ -1251,68 +1254,77 @@
return bitmapHolder->bitmap().setImmutable();
}
+static jboolean Bitmap_hasGainmap(CRITICAL_JNI_PARAMS_COMMA jlong bitmapHandle) {
+ LocalScopedBitmap bitmapHolder(bitmapHandle);
+ if (!bitmapHolder.valid()) return false;
+
+ return bitmapHolder->bitmap().hasGainmap();
+}
+
+static jobject Bitmap_extractGainmap(JNIEnv* env, jobject, jlong bitmapHandle) {
+ LocalScopedBitmap bitmapHolder(bitmapHandle);
+ if (!bitmapHolder.valid()) return nullptr;
+ if (!bitmapHolder->bitmap().hasGainmap()) return nullptr;
+
+ return Gainmap_extractFromBitmap(env, bitmapHolder->bitmap());
+}
+
///////////////////////////////////////////////////////////////////////////////
static const JNINativeMethod gBitmapMethods[] = {
- { "nativeCreate", "([IIIIIIZJ)Landroid/graphics/Bitmap;",
- (void*)Bitmap_creator },
- { "nativeCopy", "(JIZ)Landroid/graphics/Bitmap;",
- (void*)Bitmap_copy },
- { "nativeCopyAshmem", "(J)Landroid/graphics/Bitmap;",
- (void*)Bitmap_copyAshmem },
- { "nativeCopyAshmemConfig", "(JI)Landroid/graphics/Bitmap;",
- (void*)Bitmap_copyAshmemConfig },
- { "nativeGetAshmemFD", "(J)I", (void*)Bitmap_getAshmemFd },
- { "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer },
- { "nativeRecycle", "(J)V", (void*)Bitmap_recycle },
- { "nativeReconfigure", "(JIIIZ)V", (void*)Bitmap_reconfigure },
- { "nativeCompress", "(JIILjava/io/OutputStream;[B)Z",
- (void*)Bitmap_compress },
- { "nativeErase", "(JI)V", (void*)Bitmap_erase },
- { "nativeErase", "(JJJ)V", (void*)Bitmap_eraseLong },
- { "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes },
- { "nativeConfig", "(J)I", (void*)Bitmap_config },
- { "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha },
- { "nativeIsPremultiplied", "(J)Z", (void*)Bitmap_isPremultiplied},
- { "nativeSetHasAlpha", "(JZZ)V", (void*)Bitmap_setHasAlpha},
- { "nativeSetPremultiplied", "(JZ)V", (void*)Bitmap_setPremultiplied},
- { "nativeHasMipMap", "(J)Z", (void*)Bitmap_hasMipMap },
- { "nativeSetHasMipMap", "(JZ)V", (void*)Bitmap_setHasMipMap },
- { "nativeCreateFromParcel",
- "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
- (void*)Bitmap_createFromParcel },
- { "nativeWriteToParcel", "(JILandroid/os/Parcel;)Z",
- (void*)Bitmap_writeToParcel },
- { "nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;",
- (void*)Bitmap_extractAlpha },
- { "nativeGenerationId", "(J)I", (void*)Bitmap_getGenerationId },
- { "nativeGetPixel", "(JII)I", (void*)Bitmap_getPixel },
- { "nativeGetColor", "(JII)J", (void*)Bitmap_getColor },
- { "nativeGetPixels", "(J[IIIIIII)V", (void*)Bitmap_getPixels },
- { "nativeSetPixel", "(JIII)V", (void*)Bitmap_setPixel },
- { "nativeSetPixels", "(J[IIIIIII)V", (void*)Bitmap_setPixels },
- { "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V",
- (void*)Bitmap_copyPixelsToBuffer },
- { "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V",
- (void*)Bitmap_copyPixelsFromBuffer },
- { "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs },
- { "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw },
- { "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount },
- { "nativeCopyPreserveInternalConfig", "(J)Landroid/graphics/Bitmap;",
- (void*)Bitmap_copyPreserveInternalConfig },
- { "nativeWrapHardwareBufferBitmap", "(Landroid/hardware/HardwareBuffer;J)Landroid/graphics/Bitmap;",
- (void*) Bitmap_wrapHardwareBufferBitmap },
- { "nativeGetHardwareBuffer", "(J)Landroid/hardware/HardwareBuffer;",
- (void*) Bitmap_getHardwareBuffer },
- { "nativeComputeColorSpace", "(J)Landroid/graphics/ColorSpace;", (void*)Bitmap_computeColorSpace },
- { "nativeSetColorSpace", "(JJ)V", (void*)Bitmap_setColorSpace },
- { "nativeIsSRGB", "(J)Z", (void*)Bitmap_isSRGB },
- { "nativeIsSRGBLinear", "(J)Z", (void*)Bitmap_isSRGBLinear},
- { "nativeSetImmutable", "(J)V", (void*)Bitmap_setImmutable},
+ {"nativeCreate", "([IIIIIIZJ)Landroid/graphics/Bitmap;", (void*)Bitmap_creator},
+ {"nativeCopy", "(JIZ)Landroid/graphics/Bitmap;", (void*)Bitmap_copy},
+ {"nativeCopyAshmem", "(J)Landroid/graphics/Bitmap;", (void*)Bitmap_copyAshmem},
+ {"nativeCopyAshmemConfig", "(JI)Landroid/graphics/Bitmap;", (void*)Bitmap_copyAshmemConfig},
+ {"nativeGetAshmemFD", "(J)I", (void*)Bitmap_getAshmemFd},
+ {"nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer},
+ {"nativeRecycle", "(J)V", (void*)Bitmap_recycle},
+ {"nativeReconfigure", "(JIIIZ)V", (void*)Bitmap_reconfigure},
+ {"nativeCompress", "(JIILjava/io/OutputStream;[B)Z", (void*)Bitmap_compress},
+ {"nativeErase", "(JI)V", (void*)Bitmap_erase},
+ {"nativeErase", "(JJJ)V", (void*)Bitmap_eraseLong},
+ {"nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes},
+ {"nativeConfig", "(J)I", (void*)Bitmap_config},
+ {"nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha},
+ {"nativeIsPremultiplied", "(J)Z", (void*)Bitmap_isPremultiplied},
+ {"nativeSetHasAlpha", "(JZZ)V", (void*)Bitmap_setHasAlpha},
+ {"nativeSetPremultiplied", "(JZ)V", (void*)Bitmap_setPremultiplied},
+ {"nativeHasMipMap", "(J)Z", (void*)Bitmap_hasMipMap},
+ {"nativeSetHasMipMap", "(JZ)V", (void*)Bitmap_setHasMipMap},
+ {"nativeCreateFromParcel", "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
+ (void*)Bitmap_createFromParcel},
+ {"nativeWriteToParcel", "(JILandroid/os/Parcel;)Z", (void*)Bitmap_writeToParcel},
+ {"nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;", (void*)Bitmap_extractAlpha},
+ {"nativeGenerationId", "(J)I", (void*)Bitmap_getGenerationId},
+ {"nativeGetPixel", "(JII)I", (void*)Bitmap_getPixel},
+ {"nativeGetColor", "(JII)J", (void*)Bitmap_getColor},
+ {"nativeGetPixels", "(J[IIIIIII)V", (void*)Bitmap_getPixels},
+ {"nativeSetPixel", "(JIII)V", (void*)Bitmap_setPixel},
+ {"nativeSetPixels", "(J[IIIIIII)V", (void*)Bitmap_setPixels},
+ {"nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V", (void*)Bitmap_copyPixelsToBuffer},
+ {"nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V", (void*)Bitmap_copyPixelsFromBuffer},
+ {"nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs},
+ {"nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw},
+ {"nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount},
+ {"nativeCopyPreserveInternalConfig", "(J)Landroid/graphics/Bitmap;",
+ (void*)Bitmap_copyPreserveInternalConfig},
+ {"nativeWrapHardwareBufferBitmap",
+ "(Landroid/hardware/HardwareBuffer;J)Landroid/graphics/Bitmap;",
+ (void*)Bitmap_wrapHardwareBufferBitmap},
+ {"nativeGetHardwareBuffer", "(J)Landroid/hardware/HardwareBuffer;",
+ (void*)Bitmap_getHardwareBuffer},
+ {"nativeComputeColorSpace", "(J)Landroid/graphics/ColorSpace;",
+ (void*)Bitmap_computeColorSpace},
+ {"nativeSetColorSpace", "(JJ)V", (void*)Bitmap_setColorSpace},
+ {"nativeIsSRGB", "(J)Z", (void*)Bitmap_isSRGB},
+ {"nativeIsSRGBLinear", "(J)Z", (void*)Bitmap_isSRGBLinear},
+ {"nativeSetImmutable", "(J)V", (void*)Bitmap_setImmutable},
+ {"nativeExtractGainmap", "(J)Landroid/graphics/Gainmap;", (void*)Bitmap_extractGainmap},
- // ------------ @CriticalNative ----------------
- { "nativeIsImmutable", "(J)Z", (void*)Bitmap_isImmutable},
- { "nativeIsBackedByAshmem", "(J)Z", (void*)Bitmap_isBackedByAshmem}
+ // ------------ @CriticalNative ----------------
+ {"nativeIsImmutable", "(J)Z", (void*)Bitmap_isImmutable},
+ {"nativeIsBackedByAshmem", "(J)Z", (void*)Bitmap_isBackedByAshmem},
+ {"nativeHasGainmap", "(J)Z", (void*)Bitmap_hasGainmap},
};
diff --git a/libs/hwui/jni/Gainmap.cpp b/libs/hwui/jni/Gainmap.cpp
new file mode 100644
index 0000000..f2efbc7
--- /dev/null
+++ b/libs/hwui/jni/Gainmap.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2023 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 <Gainmap.h>
+
+#include "Bitmap.h"
+#include "GraphicsJNI.h"
+#include "graphics_jni_helpers.h"
+
+namespace android {
+
+static jclass gGainmap_class;
+static jmethodID gGainmap_constructorMethodID;
+
+using namespace uirenderer;
+
+static Gainmap* fromJava(jlong gainmap) {
+ return reinterpret_cast<Gainmap*>(gainmap);
+}
+
+static int getCreateFlags(const sk_sp<Bitmap>& bitmap) {
+ int flags = 0;
+ if (bitmap->info().alphaType() == kPremul_SkAlphaType) {
+ flags |= android::bitmap::kBitmapCreateFlag_Premultiplied;
+ }
+ if (!bitmap->isImmutable()) {
+ flags |= android::bitmap::kBitmapCreateFlag_Mutable;
+ }
+ return flags;
+}
+
+jobject Gainmap_extractFromBitmap(JNIEnv* env, const Bitmap& bitmap) {
+ auto gainmap = bitmap.gainmap();
+ jobject jGainmapImage;
+ size_t allocationSize;
+
+ {
+ // Scope to guard the release of nativeBitmap
+ auto nativeBitmap = gainmap->bitmap;
+ const int createFlags = getCreateFlags(nativeBitmap);
+ allocationSize = nativeBitmap->getAllocationByteCount();
+ jGainmapImage = bitmap::createBitmap(env, nativeBitmap.release(), createFlags);
+ }
+
+ // Grab a ref for the jobject
+ gainmap->incStrong(0);
+ jobject obj = env->NewObject(gGainmap_class, gGainmap_constructorMethodID, jGainmapImage,
+ gainmap.get(), allocationSize + sizeof(Gainmap), true);
+
+ if (env->ExceptionCheck() != 0) {
+ // sadtrombone
+ gainmap->decStrong(0);
+ ALOGE("*** Uncaught exception returned from Java call!\n");
+ env->ExceptionDescribe();
+ }
+ return obj;
+}
+
+static void Gainmap_destructor(Gainmap* gainmap) {
+ gainmap->decStrong(0);
+}
+
+static jlong Gainmap_getNativeFinalizer(JNIEnv*, jobject) {
+ return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Gainmap_destructor));
+}
+
+static void Gainmap_setGainmapMax(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g,
+ jfloat b) {
+ fromJava(gainmapPtr)->info.fLogRatioMax = {r, g, b, 1.f};
+}
+
+static void Gainmap_getGainmapMax(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
+ const auto ratioMax = fromJava(gainmapPtr)->info.fLogRatioMax;
+ jfloat buf[3]{ratioMax.fR, ratioMax.fG, ratioMax.fB};
+ env->SetFloatArrayRegion(components, 0, 3, buf);
+}
+
+static void Gainmap_setHdrRatioMax(JNIEnv*, jobject, jlong gainmapPtr, jfloat max) {
+ fromJava(gainmapPtr)->info.fHdrRatioMax = max;
+}
+
+static jfloat Gainmap_getHdrRatioMax(JNIEnv*, jobject, jlong gainmapPtr) {
+ return fromJava(gainmapPtr)->info.fHdrRatioMax;
+}
+
+static void Gainmap_setHdrRatioMin(JNIEnv*, jobject, jlong gainmapPtr, jfloat min) {
+ fromJava(gainmapPtr)->info.fHdrRatioMin = min;
+}
+
+static jfloat Gainmap_getHdrRatioMin(JNIEnv*, jobject, jlong gainmapPtr) {
+ return fromJava(gainmapPtr)->info.fHdrRatioMin;
+}
+
+static const JNINativeMethod gGainmapMethods[] = {
+ {"nGetFinalizer", "()J", (void*)Gainmap_getNativeFinalizer},
+ {"nSetGainmapMax", "(JFFF)V", (void*)Gainmap_setGainmapMax},
+ {"nGetGainmapMax", "(J[F)V", (void*)Gainmap_getGainmapMax},
+ {"nSetHdrRatioMax", "(JF)V", (void*)Gainmap_setHdrRatioMax},
+ {"nGetHdrRatioMax", "(J)F", (void*)Gainmap_getHdrRatioMax},
+ {"nSetHdrRatioMin", "(JF)V", (void*)Gainmap_setHdrRatioMin},
+ {"nGetHdrRatioMin", "(J)F", (void*)Gainmap_getHdrRatioMin},
+};
+
+int register_android_graphics_Gainmap(JNIEnv* env) {
+ gGainmap_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Gainmap"));
+ gGainmap_constructorMethodID =
+ GetMethodIDOrDie(env, gGainmap_class, "<init>", "(Landroid/graphics/Bitmap;JIZ)V");
+ return android::RegisterMethodsOrDie(env, "android/graphics/Gainmap", gGainmapMethods,
+ NELEM(gGainmapMethods));
+}
+
+} // namespace android
diff --git a/libs/hwui/jni/ImageDecoder.cpp b/libs/hwui/jni/ImageDecoder.cpp
index bad710d..add62b1 100644
--- a/libs/hwui/jni/ImageDecoder.cpp
+++ b/libs/hwui/jni/ImageDecoder.cpp
@@ -14,20 +14,10 @@
* limitations under the License.
*/
-#include "Bitmap.h"
-#include "BitmapFactory.h"
-#include "ByteBufferStreamAdaptor.h"
-#include "CreateJavaOutputStreamAdaptor.h"
-#include "GraphicsJNI.h"
#include "ImageDecoder.h"
-#include "NinePatchPeeker.h"
-#include "Utils.h"
-
-#include <hwui/Bitmap.h>
-#include <hwui/ImageDecoder.h>
-#include <HardwareBitmapUploader.h>
#include <FrontBufferedStream.h>
+#include <HardwareBitmapUploader.h>
#include <SkAndroidCodec.h>
#include <SkBitmap.h>
#include <SkColorSpace.h>
@@ -35,11 +25,22 @@
#include <SkRect.h>
#include <SkStream.h>
#include <SkString.h>
-
#include <androidfw/Asset.h>
#include <fcntl.h>
+#include <gui/TraceUtils.h>
+#include <hwui/Bitmap.h>
+#include <hwui/ImageDecoder.h>
#include <sys/stat.h>
+#include "Bitmap.h"
+#include "BitmapFactory.h"
+#include "ByteBufferStreamAdaptor.h"
+#include "CreateJavaOutputStreamAdaptor.h"
+#include "Gainmap.h"
+#include "GraphicsJNI.h"
+#include "NinePatchPeeker.h"
+#include "Utils.h"
+
using namespace android;
static jclass gImageDecoder_class;
@@ -246,6 +247,7 @@
jboolean requireUnpremul, jboolean preferRamOverQuality,
jboolean asAlphaMask, jlong colorSpaceHandle,
jboolean extended) {
+ ATRACE_CALL();
auto* decoder = reinterpret_cast<ImageDecoder*>(nativePtr);
if (!decoder->setTargetSize(targetWidth, targetHeight)) {
doThrowISE(env, "Could not scale to target size!");
@@ -336,10 +338,21 @@
return nullptr;
}
+ ATRACE_FORMAT("Decoding %dx%d bitmap", bitmapInfo.width(), bitmapInfo.height());
SkCodec::Result result = decoder->decode(bm.getPixels(), bm.rowBytes());
jthrowable jexception = get_and_clear_exception(env);
- int onPartialImageError = jexception ? kSourceException
- : 0; // No error.
+ int onPartialImageError = jexception ? kSourceException : 0; // No error.
+
+ // Only attempt to extract the gainmap if we're not post-processing, as we can't automatically
+ // mimic that to the gainmap and expect it to be meaningful. And also don't extract the gainmap
+ // if we're prioritizing RAM over quality, since the gainmap improves quality at the
+ // cost of RAM
+ if (result == SkCodec::kSuccess && !jpostProcess && !preferRamOverQuality) {
+ // The gainmap costs RAM to improve quality, so skip this if we're prioritizing RAM instead
+ result = decoder->extractGainmap(nativeBitmap.get());
+ jexception = get_and_clear_exception(env);
+ }
+
switch (result) {
case SkCodec::kSuccess:
// Ignore the exception, since the decode was successful anyway.
@@ -450,6 +463,10 @@
sk_sp<Bitmap> hwBitmap = Bitmap::allocateHardwareBitmap(bm);
if (hwBitmap) {
hwBitmap->setImmutable();
+ if (nativeBitmap->hasGainmap()) {
+ // TODO: Also convert to a HW gainmap image
+ hwBitmap->setGainmap(nativeBitmap->gainmap());
+ }
return bitmap::createBitmap(env, hwBitmap.release(), bitmapCreateFlags,
ninePatchChunk, ninePatchInsets);
}