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

Commit 7cc5a53c authored by Marius Renn's avatar Marius Renn Committed by Android (Google) Code Review
Browse files

Merge "Add HardwareBuffer support to Bitmaps"

parents fb301a47 b2e9f524
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -13262,6 +13262,7 @@ package android.graphics {
    method public void setPixels(int[], int, int, int, int, int, int);
    method public void setPremultiplied(boolean);
    method public void setWidth(int);
    method public static android.graphics.Bitmap wrapHardwareBuffer(android.hardware.HardwareBuffer, android.graphics.ColorSpace);
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.graphics.Bitmap> CREATOR;
    field public static final int DENSITY_NONE = 0; // 0x0
+23 −2
Original line number Diff line number Diff line
@@ -21,6 +21,10 @@
#include <hwui/Bitmap.h>
#include <renderthread/RenderProxy.h>

#include <android_runtime/android_hardware_HardwareBuffer.h>

#include <private/android/AHardwareBufferHelpers.h>

#include "core_jni_helpers.h"

#include <jni.h>
@@ -1104,8 +1108,7 @@ static jobject Bitmap_copyPreserveInternalConfig(JNIEnv* env, jobject, jlong bit

static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphicBuffer) {
    sp<GraphicBuffer> buffer(graphicBufferForJavaObject(env, graphicBuffer));
    // Bitmap::createFrom currently can only attach to a GraphicBuffer with PIXEL_FORMAT_RGBA_8888
    // format and SRGB color space.
    // Bitmap::createFrom currently assumes SRGB color space for RGBA images.
    // To support any color space, we need to pass an additional ColorSpace argument to
    // java Bitmap.createHardwareBitmap.
    sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer);
@@ -1116,6 +1119,22 @@ static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphic
    return bitmap::createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(false));
}

static jobject Bitmap_wrapHardwareBufferBitmap(JNIEnv* env, jobject, jobject hardwareBuffer,
                                               jfloatArray xyzD50, jobject transferParameters) {
    SkColorSpaceTransferFn p = GraphicsJNI::getNativeTransferParameters(env, transferParameters);
    SkMatrix44 xyzMatrix = GraphicsJNI::getNativeXYZMatrix(env, xyzD50);
    sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeRGB(p, xyzMatrix);
    AHardwareBuffer* hwBuf = android_hardware_HardwareBuffer_getNativeHardwareBuffer(env,
        hardwareBuffer);
    sp<GraphicBuffer> buffer(AHardwareBuffer_to_GraphicBuffer(hwBuf));
    sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer, colorSpace);
    if (!bitmap.get()) {
        ALOGW("failed to create hardware bitmap from hardware buffer");
        return NULL;
    }
    return bitmap::createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(false));
}

static jobject Bitmap_createGraphicBufferHandle(JNIEnv* env, jobject, jlong bitmapPtr) {
    LocalScopedBitmap bitmapHandle(bitmapPtr);
    LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(),
@@ -1195,6 +1214,8 @@ static const JNINativeMethod gBitmapMethods[] = {
        (void*)Bitmap_copyPreserveInternalConfig },
    {   "nativeCreateHardwareBitmap", "(Landroid/graphics/GraphicBuffer;)Landroid/graphics/Bitmap;",
        (void*) Bitmap_createHardwareBitmap },
    {   "nativeWrapHardwareBufferBitmap", "(Landroid/hardware/HardwareBuffer;[FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)Landroid/graphics/Bitmap;",
        (void*) Bitmap_wrapHardwareBufferBitmap },
    {   "nativeCreateGraphicBufferHandle", "(J)Landroid/graphics/GraphicBuffer;",
        (void*) Bitmap_createGraphicBufferHandle },
    {   "nativeGetColorSpace",      "(J[F[F)Z", (void*)Bitmap_getColorSpace },
+46 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.annotation.Size;
import android.annotation.UnsupportedAppUsage;
import android.annotation.WorkerThread;
import android.content.res.ResourcesImpl;
import android.hardware.HardwareBuffer;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.StrictMode;
@@ -723,6 +724,48 @@ public final class Bitmap implements Parcelable {
        return nativeCreateHardwareBitmap(graphicBuffer);
    }

    /**
     * Create a hardware bitmap backed by a {@link HardwareBuffer}.
     *
     * <p>The passed HardwareBuffer's usage flags must contain
     * {@link HardwareBuffer#USAGE_GPU_SAMPLED_IMAGE}.
     *
     * <p>The bitmap will keep a reference to the buffer so that callers can safely close the
     * HardwareBuffer without affecting the Bitmap. However the HardwareBuffer must not be
     * modified while a wrapped Bitmap is accessing it. Doing so will result in undefined behavior.
     *
     * @param hardwareBuffer The HardwareBuffer to wrap.
     * @param colorSpace The color space of the bitmap. Must be a {@link ColorSpace.Rgb} colorspace.
     *                   If null, SRGB is assumed.
     * @return A bitmap wrapping the buffer, or null if there was a problem creating the bitmap.
     * @throws IllegalArgumentException if the HardwareBuffer has an invalid usage, or an invalid
     *                                  colorspace is given.
     */
    @Nullable
    public static Bitmap wrapHardwareBuffer(@NonNull HardwareBuffer hardwareBuffer,
            @Nullable ColorSpace colorSpace) {
        if ((hardwareBuffer.getUsage() & HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE) == 0) {
            throw new IllegalArgumentException("usage flags must contain USAGE_GPU_SAMPLED_IMAGE.");
        }
        int format = hardwareBuffer.getFormat();
        ColorSpace.Rgb rgb = null;
        if (colorSpace != null) {
            if (!(colorSpace instanceof ColorSpace.Rgb)) {
                throw new IllegalArgumentException("colorSpace must be an RGB color space");
            }
            rgb = (ColorSpace.Rgb) colorSpace;
        } else {
            rgb = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
        }
        ColorSpace.Rgb.TransferParameters parameters = rgb.getTransferParameters();
        if (parameters == null) {
            throw new IllegalArgumentException("colorSpace must use an ICC "
                    + "parametric transfer function");
        }
        ColorSpace.Rgb d50 = (ColorSpace.Rgb) ColorSpace.adapt(rgb, ColorSpace.ILLUMINANT_D50);
        return nativeWrapHardwareBufferBitmap(hardwareBuffer, d50.getTransform(), parameters);
    }

    /**
     * Creates a new bitmap, scaled from an existing bitmap, when possible. If the
     * specified width and height are the same as the current width and height of
@@ -2118,6 +2161,9 @@ public final class Bitmap implements Parcelable {
    private static native int nativeGetAllocationByteCount(long nativeBitmap);
    private static native Bitmap nativeCopyPreserveInternalConfig(long nativeBitmap);
    private static native Bitmap nativeCreateHardwareBitmap(GraphicBuffer buffer);
    private static native Bitmap nativeWrapHardwareBufferBitmap(HardwareBuffer buffer,
                                                              @Size(9) float[] xyzD50,
                                                              ColorSpace.Rgb.TransferParameters p);
    private static native GraphicBuffer nativeCreateGraphicBufferHandle(long nativeBitmap);
    private static native boolean nativeGetColorSpace(long nativePtr, float[] xyz, float[] params);
    private static native boolean nativeIsSRGB(long nativePtr);
+7 −6
Original line number Diff line number Diff line
@@ -134,14 +134,15 @@ sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, SkPixelRef& pixelRef)
}

sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer) {
    PixelFormat format = graphicBuffer->getPixelFormat();
    if (!graphicBuffer.get() ||
        (format != PIXEL_FORMAT_RGBA_8888 && format != PIXEL_FORMAT_RGBA_FP16)) {
        return nullptr;
    return createFrom(graphicBuffer, SkColorSpace::MakeSRGB());
}

sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer, sk_sp<SkColorSpace> colorSpace) {
    // As we will be effectively texture-sampling the buffer (using either EGL or Vulkan), we can
    // view the colorspace as RGBA8888.
    SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(),
                                         kRGBA_8888_SkColorType, kPremul_SkAlphaType,
                                         SkColorSpace::MakeSRGB());
                                         colorSpace);
    return sk_sp<Bitmap>(new Bitmap(graphicBuffer.get(), info));
}

+2 −0
Original line number Diff line number Diff line
@@ -64,6 +64,8 @@ public:
                                              size_t rowBytes);

    static sk_sp<Bitmap> createFrom(sp<GraphicBuffer> graphicBuffer);
    static sk_sp<Bitmap> createFrom(sp<GraphicBuffer> graphicBuffer,
                                    sk_sp<SkColorSpace> colorSpace);

    static sk_sp<Bitmap> createFrom(const SkImageInfo&, SkPixelRef&);