diff --git a/api/current.txt b/api/current.txt index c12ddb8b0da84..354f85c4c5216 100644 --- a/api/current.txt +++ b/api/current.txt @@ -14054,6 +14054,37 @@ package android.hardware { method public float getZ(); } + public final class HardwareBuffer implements android.os.Parcelable { + method public static android.hardware.HardwareBuffer create(int, int, int, int, long); + method public int describeContents(); + method public void destroy(); + method public int getFormat(); + method public int getHeight(); + method public int getLayers(); + method public long getUsage(); + method public int getWidth(); + method public boolean isDestroyed(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator CREATOR; + field public static final int RGBA_8888 = 1; // 0x1 + field public static final int RGBA_FP16 = 5; // 0x5 + field public static final int RGBX_8888 = 2; // 0x2 + field public static final int RGB_565 = 4; // 0x4 + field public static final int RGB_888 = 3; // 0x3 + field public static final long USAGE0_CPU_READ = 2L; // 0x2L + field public static final long USAGE0_CPU_READ_OFTEN = 6L; // 0x6L + field public static final long USAGE0_CPU_WRITE = 32L; // 0x20L + field public static final long USAGE0_CPU_WRITE_OFTEN = 96L; // 0x60L + field public static final long USAGE0_GPU_COLOR_OUTPUT = 2048L; // 0x800L + field public static final long USAGE0_GPU_CUBEMAP = 8192L; // 0x2000L + field public static final long USAGE0_GPU_DATA_BUFFER = 16384L; // 0x4000L + field public static final long USAGE0_GPU_SAMPLED_IMAGE = 1024L; // 0x400L + field public static final long USAGE0_GPU_STORAGE_IMAGE = 3072L; // 0xc00L + field public static final long USAGE0_PROTECTED_CONTENT = 262144L; // 0x40000L + field public static final long USAGE0_SENSOR_DIRECT_DATA = 536870912L; // 0x20000000L + field public static final long USAGE0_VIDEO_ENCODE = 2097152L; // 0x200000L + } + public final class Sensor { method public int getFifoMaxEventCount(); method public int getFifoReservedEventCount(); diff --git a/api/system-current.txt b/api/system-current.txt index 23edd4b7429a1..c5093171ea8b4 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -14572,6 +14572,37 @@ package android.hardware { method public float getZ(); } + public final class HardwareBuffer implements android.os.Parcelable { + method public static android.hardware.HardwareBuffer create(int, int, int, int, long); + method public int describeContents(); + method public void destroy(); + method public int getFormat(); + method public int getHeight(); + method public int getLayers(); + method public long getUsage(); + method public int getWidth(); + method public boolean isDestroyed(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator CREATOR; + field public static final int RGBA_8888 = 1; // 0x1 + field public static final int RGBA_FP16 = 5; // 0x5 + field public static final int RGBX_8888 = 2; // 0x2 + field public static final int RGB_565 = 4; // 0x4 + field public static final int RGB_888 = 3; // 0x3 + field public static final long USAGE0_CPU_READ = 2L; // 0x2L + field public static final long USAGE0_CPU_READ_OFTEN = 6L; // 0x6L + field public static final long USAGE0_CPU_WRITE = 32L; // 0x20L + field public static final long USAGE0_CPU_WRITE_OFTEN = 96L; // 0x60L + field public static final long USAGE0_GPU_COLOR_OUTPUT = 2048L; // 0x800L + field public static final long USAGE0_GPU_CUBEMAP = 8192L; // 0x2000L + field public static final long USAGE0_GPU_DATA_BUFFER = 16384L; // 0x4000L + field public static final long USAGE0_GPU_SAMPLED_IMAGE = 1024L; // 0x400L + field public static final long USAGE0_GPU_STORAGE_IMAGE = 3072L; // 0xc00L + field public static final long USAGE0_PROTECTED_CONTENT = 262144L; // 0x40000L + field public static final long USAGE0_SENSOR_DIRECT_DATA = 536870912L; // 0x20000000L + field public static final long USAGE0_VIDEO_ENCODE = 2097152L; // 0x200000L + } + public final class Sensor { method public int getFifoMaxEventCount(); method public int getFifoReservedEventCount(); diff --git a/api/test-current.txt b/api/test-current.txt index 3026b7e73dcae..a060addfd65dc 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -14086,6 +14086,37 @@ package android.hardware { method public float getZ(); } + public final class HardwareBuffer implements android.os.Parcelable { + method public static android.hardware.HardwareBuffer create(int, int, int, int, long); + method public int describeContents(); + method public void destroy(); + method public int getFormat(); + method public int getHeight(); + method public int getLayers(); + method public long getUsage(); + method public int getWidth(); + method public boolean isDestroyed(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator CREATOR; + field public static final int RGBA_8888 = 1; // 0x1 + field public static final int RGBA_FP16 = 5; // 0x5 + field public static final int RGBX_8888 = 2; // 0x2 + field public static final int RGB_565 = 4; // 0x4 + field public static final int RGB_888 = 3; // 0x3 + field public static final long USAGE0_CPU_READ = 2L; // 0x2L + field public static final long USAGE0_CPU_READ_OFTEN = 6L; // 0x6L + field public static final long USAGE0_CPU_WRITE = 32L; // 0x20L + field public static final long USAGE0_CPU_WRITE_OFTEN = 96L; // 0x60L + field public static final long USAGE0_GPU_COLOR_OUTPUT = 2048L; // 0x800L + field public static final long USAGE0_GPU_CUBEMAP = 8192L; // 0x2000L + field public static final long USAGE0_GPU_DATA_BUFFER = 16384L; // 0x4000L + field public static final long USAGE0_GPU_SAMPLED_IMAGE = 1024L; // 0x400L + field public static final long USAGE0_GPU_STORAGE_IMAGE = 3072L; // 0xc00L + field public static final long USAGE0_PROTECTED_CONTENT = 262144L; // 0x40000L + field public static final long USAGE0_SENSOR_DIRECT_DATA = 536870912L; // 0x20000000L + field public static final long USAGE0_VIDEO_ENCODE = 2097152L; // 0x200000L + } + public final class Sensor { method public int getFifoMaxEventCount(); method public int getFifoReservedEventCount(); diff --git a/core/java/android/hardware/HardwareBuffer.aidl b/core/java/android/hardware/HardwareBuffer.aidl new file mode 100644 index 0000000000000..5bdd96677da53 --- /dev/null +++ b/core/java/android/hardware/HardwareBuffer.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2017 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.hardware; + +parcelable HardwareBuffer; diff --git a/core/java/android/hardware/HardwareBuffer.java b/core/java/android/hardware/HardwareBuffer.java new file mode 100644 index 0000000000000..fffb1d77d27c6 --- /dev/null +++ b/core/java/android/hardware/HardwareBuffer.java @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2017 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.hardware; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +import dalvik.annotation.optimization.FastNative; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import libcore.util.NativeAllocationRegistry; + +/** + * HardwareBuffer wraps a native AHardwareBuffer object, which is a low-level object + * representing a memory buffer accessible by various hardware units. HardwareBuffer allows sharing + * buffers across different application processes. In particular, HardwareBuffers may be mappable + * to memory accessibly to various hardware systems, such as the GPU, a sensor or context hub, or + * other auxiliary processing units. + * + * For more information, see the NDK documentation for AHardwareBuffer. + */ +public final class HardwareBuffer implements Parcelable { + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({RGBA_8888, RGBA_FP16, RGBX_8888, RGB_888, RGB_565}) + public @interface Format {}; + + /** Format: 8 bits each red, green, blue, alpha */ + public static final int RGBA_8888 = 1; + /** Format: 8 bits each red, green, blue, alpha, alpha is always 0xFF */ + public static final int RGBX_8888 = 2; + /** Format: 8 bits each red, green, blue, no alpha */ + public static final int RGB_888 = 3; + /** Format: 5 bits each red and blue, 6 bits green, no alpha */ + public static final int RGB_565 = 4; + /** Format: 16 bits each red, green, blue, alpha */ + public static final int RGBA_FP16 = 5; + + // Note: do not rename, this field is used by native code + private long mNativeObject; + + // Invoked on destruction + private Runnable mCleaner; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, value = {USAGE0_CPU_READ, USAGE0_CPU_READ_OFTEN, USAGE0_CPU_WRITE, + USAGE0_CPU_WRITE_OFTEN, USAGE0_GPU_SAMPLED_IMAGE, USAGE0_GPU_COLOR_OUTPUT, + USAGE0_GPU_STORAGE_IMAGE, USAGE0_GPU_CUBEMAP, USAGE0_GPU_DATA_BUFFER, + USAGE0_PROTECTED_CONTENT, USAGE0_SENSOR_DIRECT_DATA, USAGE0_VIDEO_ENCODE}) + public @interface Usage0 {}; + + /** Usage0: the buffer will sometimes be read by the CPU */ + public static final long USAGE0_CPU_READ = (1 << 1); + /** Usage0: the buffer will often be read by the CPU*/ + public static final long USAGE0_CPU_READ_OFTEN = (1 << 2 | USAGE0_CPU_READ); + /** Usage0: the buffer will sometimes be written to by the CPU */ + public static final long USAGE0_CPU_WRITE = (1 << 5); + /** Usage0: the buffer will often be written to by the CPU */ + public static final long USAGE0_CPU_WRITE_OFTEN = (1 << 6 | USAGE0_CPU_WRITE); + /** Usage0: the buffer will be read from by the GPU */ + public static final long USAGE0_GPU_SAMPLED_IMAGE = (1 << 10); + /** Usage0: the buffer will be written to by the GPU */ + public static final long USAGE0_GPU_COLOR_OUTPUT = (1 << 11); + /** Usage0: the buffer will be read from and written to by the GPU */ + public static final long USAGE0_GPU_STORAGE_IMAGE = (USAGE0_GPU_SAMPLED_IMAGE | + USAGE0_GPU_COLOR_OUTPUT); + /** Usage0: the buffer will be used as a cubemap texture */ + public static final long USAGE0_GPU_CUBEMAP = (1 << 13); + /** Usage0: the buffer will be used as a shader storage or uniform buffer object*/ + public static final long USAGE0_GPU_DATA_BUFFER = (1 << 14); + /** Usage0: the buffer must not be used outside of a protected hardware path */ + public static final long USAGE0_PROTECTED_CONTENT = (1 << 18); + /** Usage0: the buffer will be used for sensor direct data */ + public static final long USAGE0_SENSOR_DIRECT_DATA = (1 << 29); + /** Usage0: the buffer will be read by a hardware video encoder */ + public static final long USAGE0_VIDEO_ENCODE = (1 << 21); + + // The approximate size of a native AHardwareBuffer object. + private static final long NATIVE_HARDWARE_BUFFER_SIZE = 232; + /** + * Creates a new HardwareBuffer instance. + * + *

Calling this method will throw an IllegalStateException if + * format is not a supported Format type.

+ * + * @param width The width in pixels of the buffer + * @param height The height in pixels of the buffer + * @param format The format of each pixel, one of {@link #RGBA_8888}, {@link #RGBA_FP16}, + * {@link #RGBX_8888}, {@link #RGB_565}, {@link #RGB_888} + * @param layers The number of layers in the buffer + * @param usage Flags describing how the buffer will be used, one of + * {@link #USAGE0_CPU_READ}, {@link #USAGE0_CPU_READ_OFTEN}, {@link #USAGE0_CPU_WRITE}, + * {@link #USAGE0_CPU_WRITE_OFTEN}, {@link #USAGE0_GPU_SAMPLED_IMAGE}, + * {@link #USAGE0_GPU_COLOR_OUTPUT},{@link #USAGE0_GPU_STORAGE_IMAGE}, + * {@link #USAGE0_GPU_CUBEMAP}, {@link #USAGE0_GPU_DATA_BUFFER}, + * {@link #USAGE0_PROTECTED_CONTENT}, {@link #USAGE0_SENSOR_DIRECT_DATA}, + * {@link #USAGE0_VIDEO_ENCODE} + * + * @return A HardwareBuffer instance if successful, or throws an + * IllegalArgumentException if the dimensions passed are invalid (either zero, negative, or + * too large to allocate), if the format is not supported, if the requested number of layers + * is less than one or not supported, or if the passed usage flags are not a supported set. + */ + @NonNull + public static HardwareBuffer create(int width, int height, @Format int format, int layers, + @Usage0 long usage) { + if (!HardwareBuffer.isSupportedFormat(format)) { + throw new IllegalArgumentException("Invalid pixel format " + format); + } + if (width <= 0) { + throw new IllegalArgumentException("Invalid width " + width); + } + if (height <= 0) { + throw new IllegalArgumentException("Invalid height " + height); + } + if (layers <= 0) { + throw new IllegalArgumentException("Invalid layer count " + layers); + } + long nativeObject = nCreateHardwareBuffer(width, height, format, layers, usage); + if (nativeObject == 0) { + throw new IllegalArgumentException("Unable to create a HardwareBuffer, either the " + + "dimensions passed were too large, too many image layers were requested, " + + "or an invalid set of usage flags was passed"); + } + return new HardwareBuffer(nativeObject); + } + + /** + * Private use only. See {@link #create(int, int, int, int, int, long, long)}. May also be + * called from JNI using an already allocated native HardwareBuffer. + */ + private HardwareBuffer(long nativeObject) { + mNativeObject = nativeObject; + + long nativeSize = NATIVE_HARDWARE_BUFFER_SIZE; + NativeAllocationRegistry registry = new NativeAllocationRegistry( + HardwareBuffer.class.getClassLoader(), nGetNativeFinalizer(), nativeSize); + mCleaner = registry.registerNativeAllocation(this, mNativeObject); + } + + /** + * Returns the width of this buffer in pixels. + */ + public int getWidth() { + if (mNativeObject == 0) { + throw new IllegalStateException("This HardwareBuffer has been destroyed and its width " + + "cannot be obtained."); + } + return nGetWidth(mNativeObject); + } + + /** + * Returns the height of this buffer in pixels. + */ + public int getHeight() { + if (mNativeObject == 0) { + throw new IllegalStateException("This HardwareBuffer has been destroyed and its height " + + "cannot be obtained."); + } + return nGetHeight(mNativeObject); + } + + /** + * Returns the format of this buffer, one of {@link #RGBA_8888}, {@link #RGBA_FP16}, + * {@link #RGBX_8888}, {@link #RGB_565}, or {@link #RGB_888}. + */ + public int getFormat() { + if (mNativeObject == 0) { + throw new IllegalStateException("This HardwareBuffer has been destroyed and its format " + + "cannot be obtained."); + } + return nGetFormat(mNativeObject); + } + + /** + * Returns the number of layers in this buffer. + */ + public int getLayers() { + if (mNativeObject == 0) { + throw new IllegalStateException("This HardwareBuffer has been destroyed and its layer " + + "count cannot be obtained."); + } + return nGetLayers(mNativeObject); + } + + /** + * Returns the usage flags of the usage hints set on this buffer. + */ + public long getUsage() { + if (mNativeObject == 0) { + throw new IllegalStateException("This HardwareBuffer has been destroyed and its usage " + + "cannot be obtained."); + } + return nGetUsage(mNativeObject); + } + + /** + * Destroys this buffer immediately. Calling this method frees up any + * underlying native resources. After calling this method, this buffer + * must not be used in any way. + * + * @see #isDestroyed() + */ + public void destroy() { + if (mNativeObject != 0) { + mNativeObject = 0; + mCleaner.run(); + mCleaner = null; + } + } + + /** + * Indicates whether this buffer has been destroyed. A destroyed buffer + * cannot be used in any way: the buffer cannot be written to a parcel, etc. + * + * @return True if this HardwareBuffer is in a destroyed state, + * false otherwise. + * + * @see #destroy() + */ + public boolean isDestroyed() { + return mNativeObject == 0; + } + + @Override + public int describeContents() { + return Parcelable.CONTENTS_FILE_DESCRIPTOR; + } + + /** + * Flatten this object in to a Parcel. + * + *

Calling this method will throw an IllegalStateException if + * {@link #destroy()} has been previously called.

+ * + * @param dest The Parcel in which the object should be written. + * @param flags Additional flags about how the object should be written. + * May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}. + */ + @Override + public void writeToParcel(Parcel dest, int flags) { + if (mNativeObject == 0) { + throw new IllegalStateException("This HardwareBuffer has been destroyed and cannot be " + + "written to a parcel."); + } + nWriteHardwareBufferToParcel(mNativeObject, dest); + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public HardwareBuffer createFromParcel(Parcel in) { + long nativeObject = nReadHardwareBufferFromParcel(in); + if (nativeObject != 0) { + return new HardwareBuffer(nativeObject); + } + return null; + } + + public HardwareBuffer[] newArray(int size) { + return new HardwareBuffer[size]; + } + }; + + /** + * Validates whether a particular format is supported by HardwareBuffer. + * + * @param format The format to validate. + * + * @return True if format is a supported format. false otherwise. + * See {@link #create(int, int, int, int, int, long, long)}.a + */ + private static boolean isSupportedFormat(@Format int format) { + switch(format) { + case RGBA_8888: + case RGBA_FP16: + case RGBX_8888: + case RGB_565: + case RGB_888: + return true; + } + return false; + } + + private static native long nCreateHardwareBuffer(int width, int height, int format, int layers, + long usage); + private static native long nGetNativeFinalizer(); + private static native void nWriteHardwareBufferToParcel(long nativeObject, Parcel dest); + private static native long nReadHardwareBufferFromParcel(Parcel in); + @FastNative + private static native int nGetWidth(long nativeObject); + @FastNative + private static native int nGetHeight(long nativeObject); + @FastNative + private static native int nGetFormat(long nativeObject); + @FastNative + private static native int nGetLayers(long nativeObject); + @FastNative + private static native long nGetUsage(long nativeObject); +} diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 6a9ed8e4f308f..cf9441b5c69c6 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -159,6 +159,7 @@ LOCAL_SRC_FILES:= \ android_hardware_camera2_legacy_LegacyCameraDevice.cpp \ android_hardware_camera2_legacy_PerfMeasurement.cpp \ android_hardware_camera2_DngCreator.cpp \ + android_hardware_HardwareBuffer.cpp \ android_hardware_Radio.cpp \ android_hardware_SensorManager.cpp \ android_hardware_SerialPort.cpp \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index fb5d0373725a4..340f2eefa37a6 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -87,6 +87,7 @@ extern int register_android_hardware_camera2_CameraMetadata(JNIEnv *env); extern int register_android_hardware_camera2_legacy_LegacyCameraDevice(JNIEnv *env); extern int register_android_hardware_camera2_legacy_PerfMeasurement(JNIEnv *env); extern int register_android_hardware_camera2_DngCreator(JNIEnv *env); +extern int register_android_hardware_HardwareBuffer(JNIEnv *env); extern int register_android_hardware_Radio(JNIEnv *env); extern int register_android_hardware_SensorManager(JNIEnv *env); extern int register_android_hardware_SerialPort(JNIEnv *env); @@ -1373,6 +1374,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_hardware_camera2_legacy_LegacyCameraDevice), REG_JNI(register_android_hardware_camera2_legacy_PerfMeasurement), REG_JNI(register_android_hardware_camera2_DngCreator), + REG_JNI(register_android_hardware_HardwareBuffer), REG_JNI(register_android_hardware_Radio), REG_JNI(register_android_hardware_SensorManager), REG_JNI(register_android_hardware_SerialPort), diff --git a/core/jni/android_hardware_HardwareBuffer.cpp b/core/jni/android_hardware_HardwareBuffer.cpp new file mode 100644 index 0000000000000..74527d97e119d --- /dev/null +++ b/core/jni/android_hardware_HardwareBuffer.cpp @@ -0,0 +1,346 @@ +/* + * Copyright (C) 2017 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. + */ + +#define LOG_TAG "HardwareBuffer" + +#include "jni.h" +#include "JNIHelp.h" + +#include "android_os_Parcel.h" +#include "android/graphics/GraphicsJNI.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "core_jni_helpers.h" + +using namespace android; + +// ---------------------------------------------------------------------------- +// Defines +// ---------------------------------------------------------------------------- + +// Debug +static const bool kDebugGraphicBuffer = false; + +// ---------------------------------------------------------------------------- +// Types +// ---------------------------------------------------------------------------- + +static struct { + jclass clazz; + jfieldID mNativeObject; + jmethodID ctor; +} gHardwareBufferClassInfo; + +class GraphicBufferWrapper { +public: + explicit GraphicBufferWrapper(const sp& buffer) + : buffer(buffer) {} + + sp buffer; +}; + + +// ---------------------------------------------------------------------------- +// Helper functions +// ---------------------------------------------------------------------------- + +static inline bool containsBits(uint64_t mask, uint64_t bitsToCheck) { + return (mask & bitsToCheck) == bitsToCheck; +} + +// ---------------------------------------------------------------------------- +// HardwareBuffer lifecycle +// ---------------------------------------------------------------------------- + +static jlong android_hardware_HardwareBuffer_create(JNIEnv* env, jobject clazz, + jint width, jint height, jint format, jint layers, jlong usage) { + + sp composer(ComposerService::getComposerService()); + sp alloc(composer->createGraphicBufferAlloc()); + if (alloc == NULL) { + if (kDebugGraphicBuffer) { + ALOGW("createGraphicBufferAlloc() failed in HardwareBuffer.create()"); + } + return NULL; + } + + // TODO: update createGraphicBuffer to take two 64-bit values. + int pixelFormat = android_hardware_HardwareBuffer_convertToPixelFormat(format); + if (pixelFormat == 0) { + if (kDebugGraphicBuffer) { + ALOGW("createGraphicBufferAlloc() invalid pixel format in HardwareBuffer.create()"); + } + return NULL; + } + uint32_t grallocUsage = android_hardware_HardwareBuffer_convertToGrallocUsageBits(usage, 0); + status_t error; + sp buffer(alloc->createGraphicBuffer(width, height, pixelFormat, + layers, grallocUsage, &error)); + if (buffer == NULL) { + if (kDebugGraphicBuffer) { + ALOGW("createGraphicBuffer() failed in HardwareBuffer.create()"); + } + return NULL; + } + + GraphicBufferWrapper* wrapper = new GraphicBufferWrapper(buffer); + return reinterpret_cast(wrapper); +} + +static void destroyWrapper(GraphicBufferWrapper* wrapper) { + delete wrapper; +} + +static jlong android_hardware_HardwareBuffer_getNativeFinalizer(JNIEnv* env, + jobject clazz) { + return static_cast(reinterpret_cast(&destroyWrapper)); +} + +//---------------------------------------------------------------------------- +// Accessors +// ---------------------------------------------------------------------------- + +static inline GraphicBuffer* GraphicBufferWrapper_to_GraphicBuffer( + jlong nativeObject) { + return reinterpret_cast(nativeObject)->buffer.get(); +} + +static jint android_hardware_HardwareBuffer_getWidth(JNIEnv* env, jobject clazz, + jlong nativeObject) { + GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer(nativeObject); + return static_cast(buffer->getWidth()); +} + +static jint android_hardware_HardwareBuffer_getHeight(JNIEnv* env, + jobject clazz, jlong nativeObject) { + GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer(nativeObject); + return static_cast(buffer->getHeight()); +} + +static jint android_hardware_HardwareBuffer_getFormat(JNIEnv* env, + jobject clazz, jlong nativeObject) { + GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer(nativeObject); + return static_cast(android_hardware_HardwareBuffer_convertFromPixelFormat( + buffer->getPixelFormat())); +} + +static jint android_hardware_HardwareBuffer_getLayers(JNIEnv* env, + jobject clazz, jlong nativeObject) { + GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer(nativeObject); + return static_cast(buffer->getLayerCount()); +} + +static jlong android_hardware_HardwareBuffer_getUsage(JNIEnv* env, + jobject clazz, jlong nativeObject) { + GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer(nativeObject); + return android_hardware_HardwareBuffer_convertFromGrallocUsageBits( + buffer->getUsage()); +} + +// ---------------------------------------------------------------------------- +// Serialization +// ---------------------------------------------------------------------------- + +static void android_hardware_HardwareBuffer_write(JNIEnv* env, jobject clazz, + jlong nativeObject, jobject dest) { + GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer(nativeObject); + Parcel* parcel = parcelForJavaObject(env, dest); + if (parcel) { + parcel->write(*buffer); + } +} + +static jlong android_hardware_HardwareBuffer_read(JNIEnv* env, jobject clazz, + jobject in) { + Parcel* parcel = parcelForJavaObject(env, in); + if (parcel) { + sp buffer = new GraphicBuffer(); + parcel->read(*buffer); + return reinterpret_cast(new GraphicBufferWrapper(buffer)); + } + + return NULL; +} + +// ---------------------------------------------------------------------------- +// Public functions +// ---------------------------------------------------------------------------- + +namespace android { + +AHardwareBuffer* android_hardware_HardwareBuffer_getNativeHardwareBuffer( + JNIEnv* env, jobject hardwareBufferObj) { + if (env->IsInstanceOf(hardwareBufferObj, gHardwareBufferClassInfo.clazz)) { + GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer( + env->GetLongField(hardwareBufferObj, gHardwareBufferClassInfo.mNativeObject)); + return reinterpret_cast(buffer); + } else { + return nullptr; + } +} + +jobject android_hardware_HardwareBuffer_createFromAHardwareBuffer( + JNIEnv* env, AHardwareBuffer* hardwareBuffer) { + GraphicBuffer* buffer = reinterpret_cast(hardwareBuffer); + GraphicBufferWrapper* wrapper = new GraphicBufferWrapper(buffer); + jobject hardwareBufferObj = env->NewObject(gHardwareBufferClassInfo.clazz, + gHardwareBufferClassInfo.ctor, reinterpret_cast(wrapper)); + if (hardwareBufferObj == NULL) { + delete wrapper; + if (env->ExceptionCheck()) { + ALOGE("Could not create instance of HardwareBuffer from AHardwareBuffer."); + LOGE_EX(env); + env->ExceptionClear(); + } + return nullptr; + } + return hardwareBufferObj; +} + +uint32_t android_hardware_HardwareBuffer_convertFromPixelFormat(uint32_t format) { + switch (format) { + case PIXEL_FORMAT_RGBA_8888: + return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM; + case PIXEL_FORMAT_RGBX_8888: + return AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM; + case PIXEL_FORMAT_RGB_565: + return AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM; + case PIXEL_FORMAT_RGB_888: + return AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM; + case PIXEL_FORMAT_RGBA_FP16: + return AHARDWAREBUFFER_FORMAT_R16G16B16A16_SFLOAT; + default: + ALOGE("Unknown pixel format %u", format); + return 0; + } +} + +uint32_t android_hardware_HardwareBuffer_convertToPixelFormat(uint32_t format) { + switch (format) { + case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM: + return PIXEL_FORMAT_RGBA_8888; + case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM: + return PIXEL_FORMAT_RGBX_8888; + case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM: + return PIXEL_FORMAT_RGB_565; + case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM: + return PIXEL_FORMAT_RGB_888; + case AHARDWAREBUFFER_FORMAT_R16G16B16A16_SFLOAT: + return PIXEL_FORMAT_RGBA_FP16; + default: + ALOGE("Unknown AHardwareBuffer format %u", format); + return 0; + } +} + +uint32_t android_hardware_HardwareBuffer_convertToGrallocUsageBits(uint64_t usage0, + uint64_t usage1) { + uint32_t bits = 0; + if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_CPU_READ)) + bits |= GRALLOC_USAGE_SW_READ_RARELY; + if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN)) + bits |= GRALLOC_USAGE_SW_READ_OFTEN; + if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_CPU_WRITE)) + bits |= GRALLOC_USAGE_SW_WRITE_RARELY; + if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_CPU_WRITE_OFTEN)) + bits |= GRALLOC_USAGE_SW_WRITE_OFTEN; + if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_GPU_SAMPLED_IMAGE)) + bits |= GRALLOC_USAGE_HW_TEXTURE; + if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_GPU_COLOR_OUTPUT)) + bits |= GRALLOC_USAGE_HW_RENDER; + // Not sure what this should be. + if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_GPU_CUBEMAP)) bits |= 0; + //if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_GPU_DATA_BUFFER) bits |= 0; + if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_VIDEO_ENCODE)) + bits |= GRALLOC_USAGE_HW_VIDEO_ENCODER; + if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_PROTECTED_CONTENT)) + bits |= GRALLOC_USAGE_PROTECTED; + + (void)usage1; + + return bits; +} + +uint64_t android_hardware_HardwareBuffer_convertFromGrallocUsageBits(uint64_t usage0) { + uint64_t bits = 0; + if (containsBits(usage0, GRALLOC_USAGE_SW_READ_RARELY)) + bits |= AHARDWAREBUFFER_USAGE0_CPU_READ; + if (containsBits(usage0, GRALLOC_USAGE_SW_READ_OFTEN)) + bits |= AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN; + if (containsBits(usage0, GRALLOC_USAGE_SW_WRITE_RARELY)) + bits |= AHARDWAREBUFFER_USAGE0_CPU_WRITE; + if (containsBits(usage0, GRALLOC_USAGE_SW_WRITE_OFTEN)) + bits |= AHARDWAREBUFFER_USAGE0_CPU_WRITE_OFTEN; + if (containsBits(usage0, GRALLOC_USAGE_HW_TEXTURE)) + bits |= AHARDWAREBUFFER_USAGE0_GPU_SAMPLED_IMAGE; + if (containsBits(usage0, GRALLOC_USAGE_HW_RENDER)) + bits |= AHARDWAREBUFFER_USAGE0_GPU_COLOR_OUTPUT; + if (containsBits(usage0, GRALLOC_USAGE_HW_VIDEO_ENCODER)) + bits |= AHARDWAREBUFFER_USAGE0_VIDEO_ENCODE; + if (containsBits(usage0, GRALLOC_USAGE_PROTECTED)) + bits |= AHARDWAREBUFFER_USAGE0_PROTECTED_CONTENT; + + return bits; +} + +} // namespace android + +// ---------------------------------------------------------------------------- +// JNI Glue +// ---------------------------------------------------------------------------- + +const char* const kClassPathName = "android/hardware/HardwareBuffer"; + +static const JNINativeMethod gMethods[] = { + { "nCreateHardwareBuffer", "(IIIIJ)J", (void*) android_hardware_HardwareBuffer_create }, + { "nGetNativeFinalizer", "()J", (void*) android_hardware_HardwareBuffer_getNativeFinalizer }, + { "nWriteHardwareBufferToParcel", "(JLandroid/os/Parcel;)V", + (void*) android_hardware_HardwareBuffer_write }, + { "nReadHardwareBufferFromParcel", "(Landroid/os/Parcel;)J", + (void*) android_hardware_HardwareBuffer_read }, + + // --------------- @FastNative ---------------------- + { "nGetWidth", "(J)I", (void*) android_hardware_HardwareBuffer_getWidth }, + { "nGetHeight", "(J)I", (void*) android_hardware_HardwareBuffer_getHeight }, + { "nGetFormat", "(J)I", (void*) android_hardware_HardwareBuffer_getFormat }, + { "nGetLayers", "(J)I", (void*) android_hardware_HardwareBuffer_getLayers }, + { "nGetUsage", "(J)J", (void*) android_hardware_HardwareBuffer_getUsage }, +}; + +int register_android_hardware_HardwareBuffer(JNIEnv* env) { + int err = RegisterMethodsOrDie(env, kClassPathName, gMethods, + NELEM(gMethods)); + + jclass clazz = FindClassOrDie(env, "android/hardware/HardwareBuffer"); + gHardwareBufferClassInfo.clazz = MakeGlobalRefOrDie(env, clazz); + gHardwareBufferClassInfo.mNativeObject = GetFieldIDOrDie(env, + gHardwareBufferClassInfo.clazz, "mNativeObject", "J"); + gHardwareBufferClassInfo.ctor = GetMethodIDOrDie(env, + gHardwareBufferClassInfo.clazz, "", "(J)V"); + + return err; +} diff --git a/core/jni/include/android_runtime/android_hardware_HardwareBuffer.h b/core/jni/include/android_runtime/android_hardware_HardwareBuffer.h new file mode 100644 index 0000000000000..60e065cbd0e33 --- /dev/null +++ b/core/jni/include/android_runtime/android_hardware_HardwareBuffer.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef _ANDROID_HARDWARE_HARDWAREBUFFER_H +#define _ANDROID_HARDWARE_HARDWAREBUFFER_H + +#include + +#include "jni.h" + +namespace android { + +/* Gets the underlying AHardwareBuffer for a HardwareBuffer. */ +extern AHardwareBuffer* android_hardware_HardwareBuffer_getNativeHardwareBuffer( + JNIEnv* env, jobject hardwareBufferObj); + +/* Returns a HardwareBuffer wrapper for the underlying AHardwareBuffer. */ +extern jobject android_hardware_HardwareBuffer_createFromAHardwareBuffer( + JNIEnv* env, AHardwareBuffer* hardwareBuffer); + +/* Convert from HAL_PIXEL_FORMAT values to AHARDWAREBUFFER_FORMAT values. */ +extern uint32_t android_hardware_HardwareBuffer_convertFromPixelFormat( + uint32_t format); + +/* Convert from AHARDWAREBUFFER_FORMAT values to HAL_PIXEL_FORMAT values. */ +extern uint32_t android_hardware_HardwareBuffer_convertToPixelFormat( + uint32_t format); + +/* Convert from AHARDWAREBUFFER_USAGE* flags to to gralloc usage flags. */ +extern uint32_t android_hardware_HardwareBuffer_convertToGrallocUsageBits( + uint64_t usage0, uint64_t usage1); + +/* Convert from gralloc usage flags to to AHARDWAREBUFFER_USAGE0* flags. */ +extern uint64_t android_hardware_HardwareBuffer_convertFromGrallocUsageBits( + uint64_t usage0); + +} // namespace android + +#endif // _ANDROID_HARDWARE_HARDWAREBUFFER_H