diff options
| author | 2023-01-26 18:39:33 +0000 | |
|---|---|---|
| committer | 2023-01-30 21:39:55 +0000 | |
| commit | b0da4a5d0dbcd8ab5ef06139cc4717deadd96952 (patch) | |
| tree | 973d951ad183b1f9bc2f99c64283125aa9a39b7c | |
| parent | 9810a68c82b8209fdee851d5be42d78a8a4773a6 (diff) | |
Implementing Gainmap support on BRD
Test: atest BitmapRegionDecoderTest
Change-Id: Ia6285b5adf6b5484bf38063ffffbae103d36726e
| -rw-r--r-- | libs/hwui/jni/BitmapRegionDecoder.cpp | 159 | ||||
| -rw-r--r-- | libs/hwui/jni/Graphics.cpp | 3 | ||||
| -rw-r--r-- | libs/hwui/jni/GraphicsJNI.h | 6 |
3 files changed, 148 insertions, 20 deletions
diff --git a/libs/hwui/jni/BitmapRegionDecoder.cpp b/libs/hwui/jni/BitmapRegionDecoder.cpp index eb56ae310231..f93be038cc36 100644 --- a/libs/hwui/jni/BitmapRegionDecoder.cpp +++ b/libs/hwui/jni/BitmapRegionDecoder.cpp @@ -17,28 +17,139 @@ #undef LOG_TAG #define LOG_TAG "BitmapRegionDecoder" +#include "BitmapRegionDecoder.h" + +#include <HardwareBitmapUploader.h> +#include <androidfw/Asset.h> +#include <sys/stat.h> + +#include <memory> + #include "BitmapFactory.h" #include "CreateJavaOutputStreamAdaptor.h" +#include "Gainmap.h" #include "GraphicsJNI.h" -#include "Utils.h" - -#include "BitmapRegionDecoder.h" #include "SkBitmap.h" #include "SkCodec.h" #include "SkColorSpace.h" #include "SkData.h" +#include "SkGainmapInfo.h" #include "SkStream.h" +#include "SkStreamPriv.h" +#include "Utils.h" -#include <HardwareBitmapUploader.h> -#include <androidfw/Asset.h> -#include <sys/stat.h> +using namespace android; -#include <memory> +namespace android { +class BitmapRegionDecoderWrapper { +public: + static std::unique_ptr<BitmapRegionDecoderWrapper> Make(sk_sp<SkData> data) { + std::unique_ptr<skia::BitmapRegionDecoder> mainImageBRD = + skia::BitmapRegionDecoder::Make(std::move(data)); + if (!mainImageBRD) { + return nullptr; + } -using namespace android; + SkGainmapInfo gainmapInfo; + std::unique_ptr<SkStream> gainmapStream; + std::unique_ptr<skia::BitmapRegionDecoder> gainmapBRD = nullptr; + if (mainImageBRD->getAndroidGainmap(&gainmapInfo, &gainmapStream)) { + sk_sp<SkData> data = nullptr; + if (gainmapStream->getMemoryBase()) { + // It is safe to make without copy because we'll hold onto the stream. + data = SkData::MakeWithoutCopy(gainmapStream->getMemoryBase(), + gainmapStream->getLength()); + } else { + data = SkCopyStreamToData(gainmapStream.get()); + // We don't need to hold the stream anymore + gainmapStream = nullptr; + } + gainmapBRD = skia::BitmapRegionDecoder::Make(std::move(data)); + } + + return std::unique_ptr<BitmapRegionDecoderWrapper>( + new BitmapRegionDecoderWrapper(std::move(mainImageBRD), std::move(gainmapBRD), + gainmapInfo, std::move(gainmapStream))); + } + + SkEncodedImageFormat getEncodedFormat() { return mMainImageBRD->getEncodedFormat(); } + + SkColorType computeOutputColorType(SkColorType requestedColorType) { + return mMainImageBRD->computeOutputColorType(requestedColorType); + } + + sk_sp<SkColorSpace> computeOutputColorSpace(SkColorType outputColorType, + sk_sp<SkColorSpace> prefColorSpace = nullptr) { + return mMainImageBRD->computeOutputColorSpace(outputColorType, prefColorSpace); + } + + bool decodeRegion(SkBitmap* bitmap, skia::BRDAllocator* allocator, const SkIRect& desiredSubset, + int sampleSize, SkColorType colorType, bool requireUnpremul, + sk_sp<SkColorSpace> prefColorSpace) { + return mMainImageBRD->decodeRegion(bitmap, allocator, desiredSubset, sampleSize, colorType, + requireUnpremul, prefColorSpace); + } + + bool decodeGainmapRegion(sp<uirenderer::Gainmap>* outGainmap, const SkIRect& desiredSubset, + int sampleSize, bool requireUnpremul) { + SkColorType decodeColorType = mGainmapBRD->computeOutputColorType(kN32_SkColorType); + sk_sp<SkColorSpace> decodeColorSpace = + mGainmapBRD->computeOutputColorSpace(decodeColorType, nullptr); + SkBitmap bm; + HeapAllocator heapAlloc; + if (!mGainmapBRD->decodeRegion(&bm, &heapAlloc, desiredSubset, sampleSize, decodeColorType, + requireUnpremul, decodeColorSpace)) { + ALOGE("Error decoding Gainmap region"); + return false; + } + sk_sp<Bitmap> nativeBitmap(heapAlloc.getStorageObjAndReset()); + if (!nativeBitmap) { + ALOGE("OOM allocating Bitmap for Gainmap"); + return false; + } + auto gainmap = sp<uirenderer::Gainmap>::make(); + if (!gainmap) { + ALOGE("OOM allocating Gainmap"); + return false; + } + gainmap->info = mGainmapInfo; + gainmap->bitmap = std::move(nativeBitmap); + *outGainmap = std::move(gainmap); + return true; + } + + SkIRect calculateGainmapRegion(const SkIRect& mainImageRegion) { + const float scaleX = ((float)mGainmapBRD->width()) / mMainImageBRD->width(); + const float scaleY = ((float)mGainmapBRD->height()) / mMainImageBRD->height(); + // TODO: Account for rounding error? + return SkIRect::MakeLTRB(mainImageRegion.left() * scaleX, mainImageRegion.top() * scaleY, + mainImageRegion.right() * scaleX, + mainImageRegion.bottom() * scaleY); + } + + bool hasGainmap() { return mGainmapBRD != nullptr; } + + int width() const { return mMainImageBRD->width(); } + int height() const { return mMainImageBRD->height(); } + +private: + BitmapRegionDecoderWrapper(std::unique_ptr<skia::BitmapRegionDecoder> mainImageBRD, + std::unique_ptr<skia::BitmapRegionDecoder> gainmapBRD, + SkGainmapInfo info, std::unique_ptr<SkStream> stream) + : mMainImageBRD(std::move(mainImageBRD)) + , mGainmapBRD(std::move(gainmapBRD)) + , mGainmapInfo(info) + , mGainmapStream(std::move(stream)) {} + + std::unique_ptr<skia::BitmapRegionDecoder> mMainImageBRD; + std::unique_ptr<skia::BitmapRegionDecoder> mGainmapBRD; + SkGainmapInfo mGainmapInfo; + std::unique_ptr<SkStream> mGainmapStream; +}; +} // namespace android static jobject createBitmapRegionDecoder(JNIEnv* env, sk_sp<SkData> data) { - auto brd = skia::BitmapRegionDecoder::Make(std::move(data)); + auto brd = android::BitmapRegionDecoderWrapper::Make(std::move(data)); if (!brd) { doThrowIOE(env, "Image format not supported"); return nullObjectReturn("CreateBitmapRegionDecoder returned null"); @@ -136,7 +247,7 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in recycledBytes = recycledBitmap->getAllocationByteCount(); } - auto* brd = reinterpret_cast<skia::BitmapRegionDecoder*>(brdHandle); + auto* brd = reinterpret_cast<BitmapRegionDecoderWrapper*>(brdHandle); SkColorType decodeColorType = brd->computeOutputColorType(colorType); if (isHardware) { @@ -196,9 +307,22 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in GraphicsJNI::getColorSpace(env, decodeColorSpace.get(), decodeColorType)); } + sp<uirenderer::Gainmap> gainmap; + bool hasGainmap = brd->hasGainmap(); + if (hasGainmap) { + SkIRect gainmapSubset = brd->calculateGainmapRegion(subset); + if (!brd->decodeGainmapRegion(&gainmap, gainmapSubset, sampleSize, requireUnpremul)) { + // If there is an error decoding Gainmap - we don't fail. We just don't provide Gainmap + hasGainmap = false; + } + } + // If we may have reused a bitmap, we need to indicate that the pixels have changed. if (javaBitmap) { recycleAlloc.copyIfNecessary(); + if (hasGainmap) { + recycledBitmap->setGainmap(std::move(gainmap)); + } bitmap::reinitBitmap(env, javaBitmap, recycledBitmap->info(), !requireUnpremul); return javaBitmap; } @@ -209,23 +333,30 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in } if (isHardware) { sk_sp<Bitmap> hardwareBitmap = Bitmap::allocateHardwareBitmap(bitmap); + if (hasGainmap) { + hardwareBitmap->setGainmap(std::move(gainmap)); + } return bitmap::createBitmap(env, hardwareBitmap.release(), bitmapCreateFlags); } - return android::bitmap::createBitmap(env, heapAlloc.getStorageObjAndReset(), bitmapCreateFlags); + Bitmap* heapBitmap = heapAlloc.getStorageObjAndReset(); + if (hasGainmap && heapBitmap != nullptr) { + heapBitmap->setGainmap(std::move(gainmap)); + } + return android::bitmap::createBitmap(env, heapBitmap, bitmapCreateFlags); } static jint nativeGetHeight(JNIEnv* env, jobject, jlong brdHandle) { - auto* brd = reinterpret_cast<skia::BitmapRegionDecoder*>(brdHandle); + auto* brd = reinterpret_cast<BitmapRegionDecoderWrapper*>(brdHandle); return static_cast<jint>(brd->height()); } static jint nativeGetWidth(JNIEnv* env, jobject, jlong brdHandle) { - auto* brd = reinterpret_cast<skia::BitmapRegionDecoder*>(brdHandle); + auto* brd = reinterpret_cast<BitmapRegionDecoderWrapper*>(brdHandle); return static_cast<jint>(brd->width()); } static void nativeClean(JNIEnv* env, jobject, jlong brdHandle) { - auto* brd = reinterpret_cast<skia::BitmapRegionDecoder*>(brdHandle); + auto* brd = reinterpret_cast<BitmapRegionDecoderWrapper*>(brdHandle); delete brd; } diff --git a/libs/hwui/jni/Graphics.cpp b/libs/hwui/jni/Graphics.cpp index f5cd793e41c8..28d78b4474f7 100644 --- a/libs/hwui/jni/Graphics.cpp +++ b/libs/hwui/jni/Graphics.cpp @@ -516,8 +516,7 @@ int GraphicsJNI::set_metrics_int(JNIEnv* env, jobject metrics, const SkFontMetri /////////////////////////////////////////////////////////////////////////////////////////// -jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, skia::BitmapRegionDecoder* bitmap) -{ +jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, BitmapRegionDecoderWrapper* bitmap) { ALOG_ASSERT(bitmap != NULL); jobject obj = env->NewObject(gBitmapRegionDecoder_class, diff --git a/libs/hwui/jni/GraphicsJNI.h b/libs/hwui/jni/GraphicsJNI.h index c4a61ccd1e5f..6b983c10bdca 100644 --- a/libs/hwui/jni/GraphicsJNI.h +++ b/libs/hwui/jni/GraphicsJNI.h @@ -20,9 +20,7 @@ class SkCanvas; struct SkFontMetrics; namespace android { -namespace skia { - class BitmapRegionDecoder; -} +class BitmapRegionDecoderWrapper; class Canvas; class Paint; struct Typeface; @@ -119,7 +117,7 @@ public: static jobject createRegion(JNIEnv* env, SkRegion* region); static jobject createBitmapRegionDecoder(JNIEnv* env, - android::skia::BitmapRegionDecoder* bitmap); + android::BitmapRegionDecoderWrapper* bitmap); /** * Given a bitmap we natively allocate a memory block to store the contents |