Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6e35e637 authored by Derek Sollenberger's avatar Derek Sollenberger
Browse files

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
parent 38c8934b
Loading
Loading
Loading
Loading
+14 −2
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@
#include <hwui/Paint.h>
#include <hwui/Paint.h>
#include <hwui/Bitmap.h>
#include <hwui/Bitmap.h>
#include <renderthread/RenderProxy.h>
#include <renderthread/RenderProxy.h>
#include <utils/Color.h>


#include <android_runtime/android_hardware_HardwareBuffer.h>
#include <android_runtime/android_hardware_HardwareBuffer.h>


@@ -602,6 +603,14 @@ static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) {
    return static_cast<jint>(bitmap->getGenerationID());
    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) {
static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) {
    LocalScopedBitmap bitmap(bitmapHandle);
    LocalScopedBitmap bitmap(bitmapHandle);
    if (bitmap->info().alphaType() == kPremul_SkAlphaType) {
    if (bitmap->info().alphaType() == kPremul_SkAlphaType) {
@@ -1120,7 +1129,8 @@ static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphic
    sp<GraphicBuffer> buffer(graphicBufferForJavaObject(env, graphicBuffer));
    sp<GraphicBuffer> buffer(graphicBufferForJavaObject(env, graphicBuffer));
    // To support any color space, we need to pass an additional ColorSpace argument to
    // To support any color space, we need to pass an additional ColorSpace argument to
    // java Bitmap.createHardwareBitmap.
    // 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()) {
    if (!bitmap.get()) {
        ALOGW("failed to create hardware bitmap from graphic buffer");
        ALOGW("failed to create hardware bitmap from graphic buffer");
        return NULL;
        return NULL;
@@ -1133,7 +1143,8 @@ static jobject Bitmap_wrapHardwareBufferBitmap(JNIEnv* env, jobject, jobject har
    AHardwareBuffer* hwBuf = android_hardware_HardwareBuffer_getNativeHardwareBuffer(env,
    AHardwareBuffer* hwBuf = android_hardware_HardwareBuffer_getNativeHardwareBuffer(env,
        hardwareBuffer);
        hardwareBuffer);
    sp<GraphicBuffer> buffer(AHardwareBuffer_to_GraphicBuffer(hwBuf));
    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));
            GraphicsJNI::getNativeColorSpace(colorSpacePtr));
    if (!bitmap.get()) {
    if (!bitmap.get()) {
        ALOGW("failed to create hardware bitmap from hardware buffer");
        ALOGW("failed to create hardware bitmap from hardware buffer");
@@ -1193,6 +1204,7 @@ static const JNINativeMethod gBitmapMethods[] = {
    {   "nativeErase",              "(JJJ)V", (void*)Bitmap_eraseLong },
    {   "nativeErase",              "(JJJ)V", (void*)Bitmap_eraseLong },
    {   "nativeRowBytes",           "(J)I", (void*)Bitmap_rowBytes },
    {   "nativeRowBytes",           "(J)I", (void*)Bitmap_rowBytes },
    {   "nativeConfig",             "(J)I", (void*)Bitmap_config },
    {   "nativeConfig",             "(J)I", (void*)Bitmap_config },
    {   "nativeIsConfigF16",        "(J)Z", (void*)Bitmap_isConfigF16 },
    {   "nativeHasAlpha",           "(J)Z", (void*)Bitmap_hasAlpha },
    {   "nativeHasAlpha",           "(J)Z", (void*)Bitmap_hasAlpha },
    {   "nativeIsPremultiplied",    "(J)Z", (void*)Bitmap_isPremultiplied},
    {   "nativeIsPremultiplied",    "(J)Z", (void*)Bitmap_isPremultiplied},
    {   "nativeSetHasAlpha",        "(JZZ)V", (void*)Bitmap_setHasAlpha},
    {   "nativeSetHasAlpha",        "(JZZ)V", (void*)Bitmap_setHasAlpha},
+2 −1
Original line number Original line Diff line number Diff line
@@ -1011,8 +1011,9 @@ static jobject android_view_ThreadedRenderer_createHardwareBitmapFromRenderNode(
        // Continue I guess?
        // Continue I guess?
    }
    }


    SkColorType ct = uirenderer::PixelFormatToColorType(buffer->getPixelFormat());
    sk_sp<SkColorSpace> cs = uirenderer::DataSpaceToColorSpace(bufferItem.mDataSpace);
    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(),
    return bitmap::createBitmap(env, bitmap.release(),
            android::bitmap::kBitmapCreateFlag_Premultiplied);
            android::bitmap::kBitmapCreateFlag_Premultiplied);
}
}
+14 −11
Original line number Original line Diff line number Diff line
@@ -1711,20 +1711,22 @@ public final class Bitmap implements Parcelable {
     */
     */
    @Nullable
    @Nullable
    public final ColorSpace getColorSpace() {
    public final ColorSpace getColorSpace() {
        // A reconfigure can change the configuration and rgba16f is
        checkRecycled("getColorSpace called on a recycled bitmap");
        // 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);
        }

        // Cache the color space retrieval since it can be fairly expensive
        // Cache the color space retrieval since it can be fairly expensive
        if (mColorSpace == null) {
        if (mColorSpace == null) {
            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)) {
                if (nativeIsSRGB(mNativePtr)) {
                mColorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
                    mColorSpace = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB);
            } else if (getConfig() == Config.HARDWARE && nativeIsSRGBLinear(mNativePtr)) {
                } else {
                    mColorSpace = ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB);
                    mColorSpace = ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB);
                }
            } else if (nativeIsSRGB(mNativePtr)) {
                mColorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
            } else if (nativeIsSRGBLinear(mNativePtr)) {
                mColorSpace = ColorSpace.get(ColorSpace.Named.LINEAR_SRGB);
            } else {
            } else {
                float[] xyz = new float[9];
                float[] xyz = new float[9];
                float[] params = new float[7];
                float[] params = new float[7];
@@ -2127,6 +2129,7 @@ public final class Bitmap implements Parcelable {
    private static native void nativeErase(long nativeBitmap, long colorSpacePtr, long color);
    private static native void nativeErase(long nativeBitmap, long colorSpacePtr, long color);
    private static native int nativeRowBytes(long nativeBitmap);
    private static native int nativeRowBytes(long nativeBitmap);
    private static native int nativeConfig(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 int nativeGetPixel(long nativeBitmap, int x, int y);
    private static native void nativeGetPixels(long nativeBitmap, int[] pixels,
    private static native void nativeGetPixels(long nativeBitmap, int[] pixels,
+7 −11
Original line number Original line Diff line number Diff line
@@ -164,15 +164,11 @@ static SkBitmap makeHwCompatible(const FormatInfo& format, const SkBitmap& sourc
        const SkImageInfo& info = source.info();
        const SkImageInfo& info = source.info();
        bitmap.allocPixels(
        bitmap.allocPixels(
                SkImageInfo::MakeN32(info.width(), info.height(), info.alphaType(), nullptr));
                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);
        SkCanvas canvas(bitmap);
        canvas.drawColor(0);
        canvas.drawBitmap(source, 0.0f, 0.0f, nullptr);
        canvas.drawBitmap(source, 0.0f, 0.0f, nullptr);
        }

        return bitmap;
        return bitmap;
    }
    }
}
}
@@ -253,8 +249,8 @@ sk_sp<Bitmap> HardwareBitmapUploader::allocateHardwareBitmap(const SkBitmap& sou
        eglDestroySyncKHR(display, fence);
        eglDestroySyncKHR(display, fence);
    }
    }


    return Bitmap::createFrom(buffer.get(), bitmap.refColorSpace(), bitmap.alphaType(),
    return Bitmap::createFrom(buffer.get(), bitmap.colorType(), bitmap.refColorSpace(),
                              Bitmap::computePalette(bitmap));
                              bitmap.alphaType(), Bitmap::computePalette(bitmap));
}
}


void HardwareBitmapUploader::terminate() {
void HardwareBitmapUploader::terminate() {
+4 −5
Original line number Original line Diff line number Diff line
@@ -133,12 +133,11 @@ sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, SkPixelRef& pixelRef)
}
}




sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer, sk_sp<SkColorSpace> colorSpace,
sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer, SkColorType colorType,
                                 SkAlphaType alphaType, BitmapPalette palette) {
                                 sk_sp<SkColorSpace> colorSpace, SkAlphaType alphaType,
    // As we will be effectively texture-sampling the buffer (using either EGL or Vulkan), we can
                                 BitmapPalette palette) {
    // view the format as RGBA8888.
    SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(),
    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));
    return sk_sp<Bitmap>(new Bitmap(graphicBuffer.get(), info, palette));
}
}


Loading