Add Gainmap bitmap & imagedecoder
Bug: 266628247 Test: builds & boots Change-Id: I0da44e0c48cf8a6b6f95e3b62f6d5f74bd6c1eab
This commit is contained in:
@@ -93,6 +93,7 @@ public final class Bitmap implements Parcelable {
|
||||
private boolean mRecycled;
|
||||
|
||||
private ColorSpace mColorSpace;
|
||||
private Gainmap mGainmap;
|
||||
|
||||
/*package*/ int mDensity = getDefaultDensity();
|
||||
|
||||
@@ -1896,6 +1897,27 @@ public final class Bitmap implements Parcelable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this Bitmap contains a Gainmap.
|
||||
* @hide
|
||||
*/
|
||||
public boolean hasGainmap() {
|
||||
checkRecycled("Bitmap is recycled");
|
||||
return nativeHasGainmap(mNativePtr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the gainmap or null if the bitmap doesn't contain a gainmap
|
||||
* @hide
|
||||
*/
|
||||
public @Nullable Gainmap getGainmap() {
|
||||
checkRecycled("Bitmap is recycled");
|
||||
if (mGainmap == null) {
|
||||
mGainmap = nativeExtractGainmap(mNativePtr);
|
||||
}
|
||||
return mGainmap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the bitmap's pixels with the specified {@link Color}.
|
||||
*
|
||||
@@ -2380,6 +2402,8 @@ public final class Bitmap implements Parcelable {
|
||||
|
||||
private static native void nativeSetImmutable(long nativePtr);
|
||||
|
||||
private static native Gainmap nativeExtractGainmap(long nativePtr);
|
||||
|
||||
// ---------------- @CriticalNative -------------------
|
||||
|
||||
@CriticalNative
|
||||
@@ -2387,4 +2411,7 @@ public final class Bitmap implements Parcelable {
|
||||
|
||||
@CriticalNative
|
||||
private static native boolean nativeIsBackedByAshmem(long nativePtr);
|
||||
|
||||
@CriticalNative
|
||||
private static native boolean nativeHasGainmap(long nativePtr);
|
||||
}
|
||||
|
||||
127
graphics/java/android/graphics/Gainmap.java
Normal file
127
graphics/java/android/graphics/Gainmap.java
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package android.graphics;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
|
||||
import libcore.util.NativeAllocationRegistry;
|
||||
|
||||
/**
|
||||
* Gainmap represents a mechanism for augmenting an SDR image to produce an HDR one with variable
|
||||
* display adjustment capability.
|
||||
*
|
||||
* It is a combination of a set of metadata describing the gainmap, as well as either a 1 or 3
|
||||
* channel Bitmap that represents the gainmap data itself.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class Gainmap {
|
||||
private final long mNativePtr;
|
||||
private final Bitmap mGainmapImage;
|
||||
|
||||
// called from JNI and Bitmap_Delegate.
|
||||
private Gainmap(Bitmap gainmapImage, long nativeGainmap, int allocationByteCount,
|
||||
boolean fromMalloc) {
|
||||
if (nativeGainmap == 0) {
|
||||
throw new RuntimeException("internal error: native gainmap is 0");
|
||||
}
|
||||
|
||||
mGainmapImage = gainmapImage;
|
||||
mNativePtr = nativeGainmap;
|
||||
|
||||
final NativeAllocationRegistry registry;
|
||||
if (fromMalloc) {
|
||||
registry = NativeAllocationRegistry.createMalloced(
|
||||
Bitmap.class.getClassLoader(), nGetFinalizer(), allocationByteCount);
|
||||
} else {
|
||||
registry = NativeAllocationRegistry.createNonmalloced(
|
||||
Bitmap.class.getClassLoader(), nGetFinalizer(), allocationByteCount);
|
||||
}
|
||||
registry.registerNativeAllocation(this, nativeGainmap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the image data of the gainmap represented as a Bitmap
|
||||
* @return
|
||||
*/
|
||||
@NonNull
|
||||
public Bitmap getGainmapImage() {
|
||||
return mGainmapImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the gainmap max metadata. For single-plane gainmaps, r, g, and b should be the same.
|
||||
*/
|
||||
@NonNull
|
||||
public void setGainmapMax(float r, float g, float b) {
|
||||
nSetGainmapMax(mNativePtr, r, g, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the gainmap max metadata. For single-plane gainmaps, all 3 components should be the
|
||||
* same. The components are in r, g, b order.
|
||||
*/
|
||||
@NonNull
|
||||
public float[] getGainmapMax() {
|
||||
float[] ret = new float[3];
|
||||
nGetGainmapMax(mNativePtr, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum HDR ratio for the gainmap
|
||||
*/
|
||||
@NonNull
|
||||
public void setHdrRatioMax(float max) {
|
||||
nSetHdrRatioMax(mNativePtr, max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum HDR ratio for the gainmap
|
||||
*/
|
||||
@NonNull
|
||||
public float getHdrRatioMax() {
|
||||
return nGetHdrRatioMax(mNativePtr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum HDR ratio for the gainmap
|
||||
*/
|
||||
@NonNull
|
||||
public void setHdrRatioMin(float min) {
|
||||
nSetHdrRatioMin(mNativePtr, min);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum HDR ratio for the gainmap
|
||||
*/
|
||||
@NonNull
|
||||
public float getHdrRatioMin() {
|
||||
return nGetHdrRatioMin(mNativePtr);
|
||||
}
|
||||
|
||||
private static native long nGetFinalizer();
|
||||
|
||||
private static native void nSetGainmapMax(long ptr, float r, float g, float b);
|
||||
private static native void nGetGainmapMax(long ptr, float[] components);
|
||||
|
||||
private static native void nSetHdrRatioMax(long ptr, float max);
|
||||
private static native float nGetHdrRatioMax(long ptr);
|
||||
|
||||
private static native void nSetHdrRatioMin(long ptr, float min);
|
||||
private static native float nGetHdrRatioMin(long ptr);
|
||||
}
|
||||
@@ -347,6 +347,7 @@ cc_defaults {
|
||||
"jni/CreateJavaOutputStreamAdaptor.cpp",
|
||||
"jni/FontFamily.cpp",
|
||||
"jni/FontUtils.cpp",
|
||||
"jni/Gainmap.cpp",
|
||||
"jni/Graphics.cpp",
|
||||
"jni/ImageDecoder.cpp",
|
||||
"jni/Interpolator.cpp",
|
||||
|
||||
32
libs/hwui/Gainmap.h
Normal file
32
libs/hwui/Gainmap.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <SkGainmapInfo.h>
|
||||
#include <SkImage.h>
|
||||
#include <hwui/Bitmap.h>
|
||||
#include <utils/LightRefBase.h>
|
||||
|
||||
namespace android::uirenderer {
|
||||
|
||||
class Gainmap : public LightRefBase<Gainmap> {
|
||||
public:
|
||||
SkGainmapInfo info;
|
||||
sk_sp<Bitmap> bitmap;
|
||||
};
|
||||
|
||||
} // namespace android::uirenderer
|
||||
@@ -55,6 +55,7 @@ extern int register_android_graphics_ColorFilter(JNIEnv* env);
|
||||
extern int register_android_graphics_ColorSpace(JNIEnv* env);
|
||||
extern int register_android_graphics_DrawFilter(JNIEnv* env);
|
||||
extern int register_android_graphics_FontFamily(JNIEnv* env);
|
||||
extern int register_android_graphics_Gainmap(JNIEnv* env);
|
||||
extern int register_android_graphics_HardwareRendererObserver(JNIEnv* env);
|
||||
extern int register_android_graphics_Matrix(JNIEnv* env);
|
||||
extern int register_android_graphics_Paint(JNIEnv* env);
|
||||
@@ -114,6 +115,7 @@ extern int register_android_graphics_HardwareBufferRenderer(JNIEnv* env);
|
||||
REG_JNI(register_android_graphics_ColorFilter),
|
||||
REG_JNI(register_android_graphics_DrawFilter),
|
||||
REG_JNI(register_android_graphics_FontFamily),
|
||||
REG_JNI(register_android_graphics_Gainmap),
|
||||
REG_JNI(register_android_graphics_HardwareRendererObserver),
|
||||
REG_JNI(register_android_graphics_ImageDecoder),
|
||||
REG_JNI(register_android_graphics_drawable_AnimatedImageDrawable),
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <binder/IServiceManager.h>
|
||||
#endif
|
||||
|
||||
#include <Gainmap.h>
|
||||
#include <SkCanvas.h>
|
||||
#include <SkColor.h>
|
||||
#include <SkEncodedImageFormat.h>
|
||||
@@ -44,6 +45,7 @@
|
||||
#include <SkRect.h>
|
||||
#include <SkStream.h>
|
||||
#include <SkWebpEncoder.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace android {
|
||||
@@ -494,4 +496,14 @@ bool Bitmap::compress(const SkBitmap& bitmap, JavaCompressFormat format,
|
||||
|
||||
return SkEncodeImage(stream, bitmap, fm, quality);
|
||||
}
|
||||
|
||||
sp<uirenderer::Gainmap> Bitmap::gainmap() const {
|
||||
LOG_ALWAYS_FATAL_IF(!hasGainmap(), "Bitmap doesn't have a gainmap");
|
||||
return mGainmap;
|
||||
}
|
||||
|
||||
void Bitmap::setGainmap(sp<uirenderer::Gainmap>&& gainmap) {
|
||||
mGainmap = std::move(gainmap);
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
|
||||
@@ -23,6 +23,10 @@
|
||||
#include <SkPixelRef.h>
|
||||
#include <SkRefCnt.h>
|
||||
#include <cutils/compiler.h>
|
||||
#include <utils/StrongPointer.h>
|
||||
|
||||
#include <optional>
|
||||
|
||||
#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
|
||||
#include <android/hardware_buffer.h>
|
||||
#endif
|
||||
@@ -47,6 +51,7 @@ enum class BitmapPalette {
|
||||
};
|
||||
|
||||
namespace uirenderer {
|
||||
class Gainmap;
|
||||
namespace renderthread {
|
||||
class RenderThread;
|
||||
}
|
||||
@@ -119,6 +124,11 @@ public:
|
||||
void getBounds(SkRect* bounds) const;
|
||||
|
||||
bool isHardware() const { return mPixelStorageType == PixelStorageType::Hardware; }
|
||||
bool hasGainmap() const { return mGainmap.get() != nullptr; }
|
||||
|
||||
sp<uirenderer::Gainmap> gainmap() const;
|
||||
|
||||
void setGainmap(sp<uirenderer::Gainmap>&& gainmap);
|
||||
|
||||
PixelStorageType pixelStorageType() const { return mPixelStorageType; }
|
||||
|
||||
@@ -193,6 +203,8 @@ private:
|
||||
|
||||
bool mHasHardwareMipMap = false;
|
||||
|
||||
sp<uirenderer::Gainmap> mGainmap;
|
||||
|
||||
union {
|
||||
struct {
|
||||
SkPixelRef* pixelRef;
|
||||
|
||||
@@ -16,15 +16,20 @@
|
||||
|
||||
#include "ImageDecoder.h"
|
||||
|
||||
#include <hwui/Bitmap.h>
|
||||
#include <log/log.h>
|
||||
|
||||
#include <Gainmap.h>
|
||||
#include <SkAndroidCodec.h>
|
||||
#include <SkBitmap.h>
|
||||
#include <SkBlendMode.h>
|
||||
#include <SkCanvas.h>
|
||||
#include <SkEncodedOrigin.h>
|
||||
#include <SkGainmapInfo.h>
|
||||
#include <SkPaint.h>
|
||||
#include <SkStream.h>
|
||||
#include <hwui/Bitmap.h>
|
||||
#include <log/log.h>
|
||||
#include <utils/Trace.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#undef LOG_TAG
|
||||
#define LOG_TAG "ImageDecoder"
|
||||
@@ -195,7 +200,7 @@ SkImageInfo ImageDecoder::getOutputInfo() const {
|
||||
}
|
||||
|
||||
bool ImageDecoder::swapWidthHeight() const {
|
||||
return SkEncodedOriginSwapsWidthHeight(mCodec->codec()->getOrigin());
|
||||
return SkEncodedOriginSwapsWidthHeight(getOrigin());
|
||||
}
|
||||
|
||||
int ImageDecoder::width() const {
|
||||
@@ -316,7 +321,7 @@ SkCodec::FrameInfo ImageDecoder::getCurrentFrameInfo() {
|
||||
info.fFrameRect = SkIRect::MakeSize(dims);
|
||||
}
|
||||
|
||||
if (auto origin = mCodec->codec()->getOrigin(); origin != kDefault_SkEncodedOrigin) {
|
||||
if (auto origin = getOrigin(); origin != kDefault_SkEncodedOrigin) {
|
||||
if (SkEncodedOriginSwapsWidthHeight(origin)) {
|
||||
dims = swapped(dims);
|
||||
}
|
||||
@@ -400,7 +405,7 @@ SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) {
|
||||
// FIXME: Use scanline decoding on only a couple lines to save memory. b/70709380.
|
||||
SkBitmap tmp;
|
||||
const bool scale = mDecodeSize != mTargetSize;
|
||||
const auto origin = mCodec->codec()->getOrigin();
|
||||
const auto origin = getOrigin();
|
||||
const bool handleOrigin = origin != kDefault_SkEncodedOrigin;
|
||||
SkMatrix outputMatrix;
|
||||
if (scale || handleOrigin || mCropRect) {
|
||||
@@ -455,12 +460,15 @@ SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) {
|
||||
mOptions.fZeroInitialized = SkCodec::kYes_ZeroInitialized;
|
||||
}
|
||||
|
||||
ATRACE_BEGIN("getAndroidPixels");
|
||||
auto result = mCodec->getAndroidPixels(decodeInfo, decodePixels, decodeRowBytes, &mOptions);
|
||||
ATRACE_END();
|
||||
|
||||
// The next call to decode() may not provide zero initialized memory.
|
||||
mOptions.fZeroInitialized = SkCodec::kNo_ZeroInitialized;
|
||||
|
||||
if (scale || handleOrigin || mCropRect) {
|
||||
ATRACE_NAME("Handling scale/origin/crop");
|
||||
SkBitmap scaledBm;
|
||||
if (!scaledBm.installPixels(outputInfo, pixels, rowBytes)) {
|
||||
return SkCodec::kInternalError;
|
||||
@@ -478,3 +486,71 @@ SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) {
|
||||
return result;
|
||||
}
|
||||
|
||||
SkCodec::Result ImageDecoder::extractGainmap(Bitmap* destination) {
|
||||
ATRACE_CALL();
|
||||
SkGainmapInfo gainmapInfo;
|
||||
std::unique_ptr<SkStream> gainmapStream;
|
||||
{
|
||||
ATRACE_NAME("getAndroidGainmap");
|
||||
if (!mCodec->getAndroidGainmap(&gainmapInfo, &gainmapStream)) {
|
||||
return SkCodec::kSuccess;
|
||||
}
|
||||
}
|
||||
auto gainmapCodec = SkAndroidCodec::MakeFromStream(std::move(gainmapStream));
|
||||
if (!gainmapCodec) {
|
||||
ALOGW("Failed to create codec for gainmap stream");
|
||||
return SkCodec::kInvalidInput;
|
||||
}
|
||||
ImageDecoder decoder{std::move(gainmapCodec)};
|
||||
// Gainmap inherits the origin of the containing image
|
||||
decoder.mOverrideOrigin.emplace(getOrigin());
|
||||
|
||||
const bool isScaled = width() != mTargetSize.width() || height() != mTargetSize.height();
|
||||
|
||||
if (isScaled) {
|
||||
float scaleX = (float)mTargetSize.width() / width();
|
||||
float scaleY = (float)mTargetSize.height() / height();
|
||||
decoder.setTargetSize(decoder.width() * scaleX, decoder.height() * scaleY);
|
||||
}
|
||||
|
||||
if (mCropRect) {
|
||||
float sX = decoder.mTargetSize.width() / (float)mTargetSize.width();
|
||||
float sY = decoder.mTargetSize.height() / (float)mTargetSize.height();
|
||||
SkIRect crop = *mCropRect;
|
||||
// TODO: Tweak rounding?
|
||||
crop.fLeft *= sX;
|
||||
crop.fRight *= sX;
|
||||
crop.fTop *= sY;
|
||||
crop.fBottom *= sY;
|
||||
decoder.setCropRect(&crop);
|
||||
}
|
||||
|
||||
SkImageInfo bitmapInfo = decoder.getOutputInfo();
|
||||
|
||||
SkBitmap bm;
|
||||
if (!bm.setInfo(bitmapInfo)) {
|
||||
ALOGE("Failed to setInfo properly");
|
||||
return SkCodec::kInternalError;
|
||||
}
|
||||
|
||||
// TODO: We don't currently parcel the gainmap, but if we should then also support
|
||||
// the shared allocator
|
||||
sk_sp<Bitmap> nativeBitmap = Bitmap::allocateHeapBitmap(&bm);
|
||||
if (!nativeBitmap) {
|
||||
ALOGE("OOM allocating Bitmap with dimensions %i x %i", bitmapInfo.width(),
|
||||
bitmapInfo.height());
|
||||
return SkCodec::kInternalError;
|
||||
}
|
||||
|
||||
SkCodec::Result result = decoder.decode(bm.getPixels(), bm.rowBytes());
|
||||
bm.setImmutable();
|
||||
|
||||
if (result == SkCodec::kSuccess) {
|
||||
auto gainmap = sp<uirenderer::Gainmap>::make();
|
||||
gainmap->info = gainmapInfo;
|
||||
gainmap->bitmap = std::move(nativeBitmap);
|
||||
destination->setGainmap(std::move(gainmap));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -79,6 +79,8 @@ public:
|
||||
// Set whether the ImageDecoder should handle RestorePrevious frames.
|
||||
void setHandleRestorePrevious(bool handle);
|
||||
|
||||
SkCodec::Result extractGainmap(Bitmap* destination);
|
||||
|
||||
private:
|
||||
// State machine for keeping track of how to handle RestorePrevious (RP)
|
||||
// frames in decode().
|
||||
@@ -115,6 +117,7 @@ private:
|
||||
RestoreState mRestoreState;
|
||||
sk_sp<Bitmap> mRestoreFrame;
|
||||
std::optional<SkIRect> mCropRect;
|
||||
std::optional<SkEncodedOrigin> mOverrideOrigin;
|
||||
|
||||
ImageDecoder(const ImageDecoder&) = delete;
|
||||
ImageDecoder& operator=(const ImageDecoder&) = delete;
|
||||
@@ -124,6 +127,10 @@ private:
|
||||
bool swapWidthHeight() const;
|
||||
// Store/restore a frame if necessary. Returns false on error.
|
||||
bool handleRestorePrevious(const SkImageInfo&, void* pixels, size_t rowBytes);
|
||||
|
||||
SkEncodedOrigin getOrigin() const {
|
||||
return mOverrideOrigin.has_value() ? *mOverrideOrigin : mCodec->codec()->getOrigin();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
128
libs/hwui/jni/Bitmap.cpp
Executable file → Normal file
128
libs/hwui/jni/Bitmap.cpp
Executable file → Normal file
@@ -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 @@ static jmethodID gBitmap_reinitMethodID;
|
||||
|
||||
namespace android {
|
||||
|
||||
jobject Gainmap_extractFromBitmap(JNIEnv* env, const Bitmap& bitmap);
|
||||
|
||||
class BitmapWrapper {
|
||||
public:
|
||||
explicit BitmapWrapper(Bitmap* bitmap)
|
||||
@@ -1251,68 +1254,77 @@ static void Bitmap_setImmutable(JNIEnv* env, jobject, jlong bitmapHandle) {
|
||||
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},
|
||||
|
||||
};
|
||||
|
||||
|
||||
125
libs/hwui/jni/Gainmap.cpp
Normal file
125
libs/hwui/jni/Gainmap.cpp
Normal file
@@ -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
|
||||
@@ -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 @@ static jobject ImageDecoder_nDecodeBitmap(JNIEnv* env, jobject /*clazz*/, jlong
|
||||
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 @@ static jobject ImageDecoder_nDecodeBitmap(JNIEnv* env, jobject /*clazz*/, jlong
|
||||
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 @@ static jobject ImageDecoder_nDecodeBitmap(JNIEnv* env, jobject /*clazz*/, jlong
|
||||
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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user