From 0a0f23163a7a62900d46c7f81d109320d73d6c6b Mon Sep 17 00:00:00 2001 From: sergeyv Date: Wed, 4 Jan 2017 13:58:52 -0800 Subject: Move GraphicBuffer to graphics package Test: locally tested Bitmap.createHardwareBitmap method bug: 30999911 Change-Id: Iad432577f26f2362ede9e77cd8a5425c010692e5 --- core/java/android/view/GraphicBuffer.aidl | 19 -- core/java/android/view/GraphicBuffer.java | 304 -------------------- core/jni/Android.mk | 2 +- core/jni/AndroidRuntime.cpp | 4 +- core/jni/android/graphics/Bitmap.cpp | 13 + core/jni/android/graphics/GraphicBuffer.cpp | 305 +++++++++++++++++++++ core/jni/android/graphics/GraphicBuffer.h | 27 ++ core/jni/android_view_GraphicBuffer.cpp | 320 ---------------------- core/jni/android_view_GraphicBuffer.h | 27 -- core/jni/android_view_ThreadedRenderer.cpp | 1 - graphics/java/android/graphics/Bitmap.java | 12 + graphics/java/android/graphics/GraphicBuffer.aidl | 19 ++ graphics/java/android/graphics/GraphicBuffer.java | 289 +++++++++++++++++++ 13 files changed, 668 insertions(+), 674 deletions(-) delete mode 100644 core/java/android/view/GraphicBuffer.aidl delete mode 100644 core/java/android/view/GraphicBuffer.java create mode 100644 core/jni/android/graphics/GraphicBuffer.cpp create mode 100644 core/jni/android/graphics/GraphicBuffer.h delete mode 100644 core/jni/android_view_GraphicBuffer.cpp delete mode 100644 core/jni/android_view_GraphicBuffer.h create mode 100644 graphics/java/android/graphics/GraphicBuffer.aidl create mode 100644 graphics/java/android/graphics/GraphicBuffer.java diff --git a/core/java/android/view/GraphicBuffer.aidl b/core/java/android/view/GraphicBuffer.aidl deleted file mode 100644 index 6dc6bede0dee..000000000000 --- a/core/java/android/view/GraphicBuffer.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2013 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.view; - -parcelable GraphicBuffer; diff --git a/core/java/android/view/GraphicBuffer.java b/core/java/android/view/GraphicBuffer.java deleted file mode 100644 index 64611d0bfd68..000000000000 --- a/core/java/android/view/GraphicBuffer.java +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Copyright (C) 2013 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.view; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.PixelFormat; -import android.graphics.Rect; -import android.os.Parcel; -import android.os.Parcelable; - -/** - * Simple wrapper for the native GraphicBuffer class. - * - * @hide - */ -@SuppressWarnings("UnusedDeclaration") -public class GraphicBuffer implements Parcelable { - // Note: keep usage flags in sync with GraphicBuffer.h and gralloc.h - public static final int USAGE_SW_READ_NEVER = 0x0; - public static final int USAGE_SW_READ_RARELY = 0x2; - public static final int USAGE_SW_READ_OFTEN = 0x3; - public static final int USAGE_SW_READ_MASK = 0xF; - - public static final int USAGE_SW_WRITE_NEVER = 0x0; - public static final int USAGE_SW_WRITE_RARELY = 0x20; - public static final int USAGE_SW_WRITE_OFTEN = 0x30; - public static final int USAGE_SW_WRITE_MASK = 0xF0; - - public static final int USAGE_SOFTWARE_MASK = USAGE_SW_READ_MASK | USAGE_SW_WRITE_MASK; - - public static final int USAGE_PROTECTED = 0x4000; - - public static final int USAGE_HW_TEXTURE = 0x100; - public static final int USAGE_HW_RENDER = 0x200; - public static final int USAGE_HW_2D = 0x400; - public static final int USAGE_HW_COMPOSER = 0x800; - public static final int USAGE_HW_VIDEO_ENCODER = 0x10000; - public static final int USAGE_HW_MASK = 0x71F00; - - private final int mWidth; - private final int mHeight; - private final int mFormat; - private final int mUsage; - // Note: do not rename, this field is used by native code - private final long mNativeObject; - - // These two fields are only used by lock/unlockCanvas() - private Canvas mCanvas; - private int mSaveCount; - - // If set to true, this GraphicBuffer instance cannot be used anymore - private boolean mDestroyed; - - /** - * Creates new GraphicBuffer instance. This method will return null - * if the buffer cannot be created. - * - * @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 as specified in {@link PixelFormat} - * @param usage Hint indicating how the buffer will be used - * - * @return A GraphicBuffer instance or null - */ - public static GraphicBuffer create(int width, int height, int format, int usage) { - long nativeObject = nCreateGraphicBuffer(width, height, format, usage); - if (nativeObject != 0) { - return new GraphicBuffer(width, height, format, usage, nativeObject); - } - return null; - } - - /** - * Private use only. See {@link #create(int, int, int, int)}. - */ - private GraphicBuffer(int width, int height, int format, int usage, long nativeObject) { - mWidth = width; - mHeight = height; - mFormat = format; - mUsage = usage; - mNativeObject = nativeObject; - } - - /** - * Returns the width of this buffer in pixels. - */ - public int getWidth() { - return mWidth; - } - - /** - * Returns the height of this buffer in pixels. - */ - public int getHeight() { - return mHeight; - } - - /** - * Returns the pixel format of this buffer. The pixel format must be one of - * the formats defined in {@link PixelFormat}. - */ - public int getFormat() { - return mFormat; - } - - /** - * Returns the usage hint set on this buffer. - */ - public int getUsage() { - return mUsage; - } - - /** - *

Start editing the pixels in the buffer. A null is returned if the buffer - * cannot be locked for editing.

- * - *

The content of the buffer is preserved between unlockCanvas() - * and lockCanvas().

- * - *

If this method is called after {@link #destroy()}, the return value will - * always be null.

- * - * @return A Canvas used to draw into the buffer, or null. - * - * @see #lockCanvas(android.graphics.Rect) - * @see #unlockCanvasAndPost(android.graphics.Canvas) - * @see #isDestroyed() - */ - public Canvas lockCanvas() { - return lockCanvas(null); - } - - /** - * Just like {@link #lockCanvas()} but allows specification of a dirty - * rectangle. - * - *

If this method is called after {@link #destroy()}, the return value will - * always be null.

- * - * @param dirty Area of the buffer that may be modified. - - * @return A Canvas used to draw into the surface, or null. - * - * @see #lockCanvas() - * @see #unlockCanvasAndPost(android.graphics.Canvas) - * @see #isDestroyed() - */ - public Canvas lockCanvas(Rect dirty) { - if (mDestroyed) { - return null; - } - - if (mCanvas == null) { - mCanvas = new Canvas(); - } - - if (nLockCanvas(mNativeObject, mCanvas, dirty)) { - mSaveCount = mCanvas.save(); - return mCanvas; - } - - return null; - } - - /** - * Finish editing pixels in the buffer. - * - *

This method doesn't do anything if {@link #destroy()} was - * previously called.

- * - * @param canvas The Canvas previously returned by lockCanvas() - * - * @see #lockCanvas() - * @see #lockCanvas(android.graphics.Rect) - * @see #isDestroyed() - */ - public void unlockCanvasAndPost(Canvas canvas) { - if (!mDestroyed && mCanvas != null && canvas == mCanvas) { - canvas.restoreToCount(mSaveCount); - mSaveCount = 0; - - nUnlockCanvasAndPost(mNativeObject, mCanvas); - } - } - - /** - * Destroyes 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 ({@link #lockCanvas()} must not be called, - * etc.) - * - * @see #isDestroyed() - */ - public void destroy() { - if (!mDestroyed) { - mDestroyed = true; - nDestroyGraphicBuffer(mNativeObject); - } - } - - /** - * Indicates whether this buffer has been destroyed. A destroyed buffer - * cannot be used in any way: locking a Canvas will return null, the buffer - * cannot be written to a parcel, etc. - * - * @return True if this GraphicBuffer is in a destroyed state, - * false otherwise. - * - * @see #destroy() - */ - public boolean isDestroyed() { - return mDestroyed; - } - - @Override - protected void finalize() throws Throwable { - try { - if (!mDestroyed) nDestroyGraphicBuffer(mNativeObject); - } finally { - super.finalize(); - } - } - - @Override - public int describeContents() { - return 0; - } - - /** - * 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 (mDestroyed) { - throw new IllegalStateException("This GraphicBuffer has been destroyed and cannot be " - + "written to a parcel."); - } - - dest.writeInt(mWidth); - dest.writeInt(mHeight); - dest.writeInt(mFormat); - dest.writeInt(mUsage); - nWriteGraphicBufferToParcel(mNativeObject, dest); - } - - /** - * Create hardware bitmap backed by this GraphicBuffer. - * - * @return Bitmap or null if this GraphicBuffer has unsupported PixelFormat. - * currently PIXEL_FORMAT_RGBA_8888 is the only supported format - */ - public Bitmap createHardwareBitmap() { - return nCreateHardwareBitmap(mNativeObject); - } - - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public GraphicBuffer createFromParcel(Parcel in) { - int width = in.readInt(); - int height = in.readInt(); - int format = in.readInt(); - int usage = in.readInt(); - long nativeObject = nReadGraphicBufferFromParcel(in); - if (nativeObject != 0) { - return new GraphicBuffer(width, height, format, usage, nativeObject); - } - return null; - } - - public GraphicBuffer[] newArray(int size) { - return new GraphicBuffer[size]; - } - }; - - private static native long nCreateGraphicBuffer(int width, int height, int format, int usage); - private static native void nDestroyGraphicBuffer(long nativeObject); - private static native void nWriteGraphicBufferToParcel(long nativeObject, Parcel dest); - private static native long nReadGraphicBufferFromParcel(Parcel in); - private static native boolean nLockCanvas(long nativeObject, Canvas canvas, Rect dirty); - private static native boolean nUnlockCanvasAndPost(long nativeObject, Canvas canvas); - private static native Bitmap nCreateHardwareBitmap(long nativeObject); -} diff --git a/core/jni/Android.mk b/core/jni/Android.mk index a13ebaf55cf4..0d1b803d3bf3 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -60,7 +60,6 @@ LOCAL_SRC_FILES:= \ android_graphics_drawable_VectorDrawable.cpp \ android_view_DisplayEventReceiver.cpp \ android_view_DisplayListCanvas.cpp \ - android_view_GraphicBuffer.cpp \ android_view_HardwareLayer.cpp \ android_view_InputChannel.cpp \ android_view_InputDevice.cpp \ @@ -120,6 +119,7 @@ LOCAL_SRC_FILES:= \ android/graphics/FontFamily.cpp \ android/graphics/CreateJavaOutputStreamAdaptor.cpp \ android/graphics/GIFMovie.cpp \ + android/graphics/GraphicBuffer.cpp \ android/graphics/Graphics.cpp \ android/graphics/HarfBuzzNGFaceSkia.cpp \ android/graphics/Interpolator.cpp \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 6c9a764c9be9..c195cfe23bfb 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -57,6 +57,7 @@ extern int register_android_graphics_BitmapFactory(JNIEnv*); extern int register_android_graphics_BitmapRegionDecoder(JNIEnv*); extern int register_android_graphics_Camera(JNIEnv* env); extern int register_android_graphics_CreateJavaOutputStreamAdaptor(JNIEnv* env); +extern int register_android_graphics_GraphicBuffer(JNIEnv* env); extern int register_android_graphics_Graphics(JNIEnv* env); extern int register_android_graphics_Interpolator(JNIEnv* env); extern int register_android_graphics_MaskFilter(JNIEnv* env); @@ -134,7 +135,6 @@ extern int register_android_graphics_pdf_PdfEditor(JNIEnv* env); extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env); extern int register_android_view_DisplayEventReceiver(JNIEnv* env); extern int register_android_view_DisplayListCanvas(JNIEnv* env); -extern int register_android_view_GraphicBuffer(JNIEnv* env); extern int register_android_view_HardwareLayer(JNIEnv* env); extern int register_android_view_RenderNode(JNIEnv* env); extern int register_android_view_RenderNodeAnimator(JNIEnv* env); @@ -1296,7 +1296,6 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_view_DisplayEventReceiver), REG_JNI(register_android_view_RenderNode), REG_JNI(register_android_view_RenderNodeAnimator), - REG_JNI(register_android_view_GraphicBuffer), REG_JNI(register_android_view_DisplayListCanvas), REG_JNI(register_android_view_HardwareLayer), REG_JNI(register_android_view_ThreadedRenderer), @@ -1328,6 +1327,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_graphics_ColorFilter), REG_JNI(register_android_graphics_DrawFilter), REG_JNI(register_android_graphics_FontFamily), + REG_JNI(register_android_graphics_GraphicBuffer), REG_JNI(register_android_graphics_Interpolator), REG_JNI(register_android_graphics_MaskFilter), REG_JNI(register_android_graphics_Matrix), diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index 59cbc939890a..bea2b8c53e2f 100755 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -1,6 +1,7 @@ #define LOG_TAG "Bitmap" #include "Bitmap.h" +#include "GraphicBuffer.h" #include "SkBitmap.h" #include "SkPixelRef.h" #include "SkImageEncoder.h" @@ -1308,6 +1309,16 @@ static jobject Bitmap_nativeCopyPreserveInternalConfig(JNIEnv* env, jobject, jlo return createBitmap(env, allocator.getStorageObjAndReset(), kBitmapCreateFlag_None); } +static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphicBuffer) { + sp buffer(graphicBufferForJavaObject(env, graphicBuffer)); + sk_sp bitmap = Bitmap::createFrom(buffer); + if (!bitmap.get()) { + ALOGW("failed to create hardware bitmap from graphic buffer"); + return NULL; + } + return bitmap::createBitmap(env, bitmap.release(), android::bitmap::kBitmapCreateFlag_None); +} + /////////////////////////////////////////////////////////////////////////////// static jclass make_globalref(JNIEnv* env, const char classname[]) { @@ -1368,6 +1379,8 @@ static const JNINativeMethod gBitmapMethods[] = { { "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount }, { "nativeCopyPreserveInternalConfig", "(J)Landroid/graphics/Bitmap;", (void*)Bitmap_nativeCopyPreserveInternalConfig }, + { "nativeCreateHardwareBitmap", "(Landroid/graphics/GraphicBuffer;)Landroid/graphics/Bitmap;", + (void*) Bitmap_createHardwareBitmap } }; int register_android_graphics_Bitmap(JNIEnv* env) diff --git a/core/jni/android/graphics/GraphicBuffer.cpp b/core/jni/android/graphics/GraphicBuffer.cpp new file mode 100644 index 000000000000..6cc710964050 --- /dev/null +++ b/core/jni/android/graphics/GraphicBuffer.cpp @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2013 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 "GraphicBuffer" + +#include "jni.h" +#include "JNIHelp.h" + +#include "android_os_Parcel.h" +#include "GraphicBuffer.h" +#include "GraphicsJNI.h" + +#include + +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include "core_jni_helpers.h" + +namespace android { + +// ---------------------------------------------------------------------------- +// Defines +// ---------------------------------------------------------------------------- + +// Debug +static const bool kDebugGraphicBuffer = false; + +#define LOCK_CANVAS_USAGE (GraphicBuffer::USAGE_SW_READ_OFTEN | GraphicBuffer::USAGE_SW_WRITE_OFTEN) + +// ---------------------------------------------------------------------------- +// JNI Helpers +// ---------------------------------------------------------------------------- + +static struct { + jfieldID mNativeObject; +} gGraphicBufferClassInfo; + +static struct { + jmethodID set; + jfieldID left; + jfieldID top; + jfieldID right; + jfieldID bottom; +} gRectClassInfo; + +#define GET_INT(object, field) \ + env->GetIntField(object, field) + +#define SET_INT(object, field, value) \ + env->SetIntField(object, field, value) + +#define GET_LONG(object, field) \ + env->GetLongField(object, field) + +#define SET_LONG(object, field, value) \ + env->SetLongField(object, field, value) + +#define INVOKEV(object, method, ...) \ + env->CallVoidMethod(object, method, __VA_ARGS__) + +// ---------------------------------------------------------------------------- +// Types +// ---------------------------------------------------------------------------- + +class GraphicBufferWrapper { +public: + explicit GraphicBufferWrapper(const sp& buffer): buffer(buffer) { + } + + sp buffer; +}; + +// ---------------------------------------------------------------------------- +// GraphicBuffer lifecycle +// ---------------------------------------------------------------------------- + +static jlong android_graphics_GraphicBuffer_create(JNIEnv* env, jobject clazz, + jint width, jint height, jint format, jint usage) { + + sp composer(ComposerService::getComposerService()); + sp alloc(composer->createGraphicBufferAlloc()); + if (alloc == NULL) { + if (kDebugGraphicBuffer) { + ALOGW("createGraphicBufferAlloc() failed in GraphicBuffer.create()"); + } + return NULL; + } + + status_t error; + sp buffer(alloc->createGraphicBuffer(width, height, format, 1, usage, &error)); + if (buffer == NULL) { + if (kDebugGraphicBuffer) { + ALOGW("createGraphicBuffer() failed in GraphicBuffer.create()"); + } + return NULL; + } + + GraphicBufferWrapper* wrapper = new GraphicBufferWrapper(buffer); + return reinterpret_cast(wrapper); +} + +static void android_graphics_GraphicBuffer_destroy(JNIEnv* env, jobject clazz, + jlong wrapperHandle) { + GraphicBufferWrapper* wrapper = + reinterpret_cast(wrapperHandle); + delete wrapper; +} + +// ---------------------------------------------------------------------------- +// Canvas management +// ---------------------------------------------------------------------------- + +static inline SkColorType convertPixelFormat(int32_t format) { + switch (format) { + case PIXEL_FORMAT_RGBA_8888: + return kN32_SkColorType; + case PIXEL_FORMAT_RGBX_8888: + return kN32_SkColorType; + case PIXEL_FORMAT_RGBA_FP16: + return kRGBA_F16_SkColorType; + case PIXEL_FORMAT_RGB_565: + return kRGB_565_SkColorType; + default: + return kUnknown_SkColorType; + } +} + +static jboolean android_graphics_GraphicBuffer_lockCanvas(JNIEnv* env, jobject, + jlong wrapperHandle, jobject canvas, jobject dirtyRect) { + + GraphicBufferWrapper* wrapper = + reinterpret_cast(wrapperHandle); + if (!wrapper) { + return JNI_FALSE; + } + + sp buffer(wrapper->buffer); + + Rect rect(Rect::EMPTY_RECT); + if (dirtyRect) { + rect.left = GET_INT(dirtyRect, gRectClassInfo.left); + rect.top = GET_INT(dirtyRect, gRectClassInfo.top); + rect.right = GET_INT(dirtyRect, gRectClassInfo.right); + rect.bottom = GET_INT(dirtyRect, gRectClassInfo.bottom); + } else { + rect.set(Rect(buffer->getWidth(), buffer->getHeight())); + } + + void* bits = NULL; + status_t status = buffer->lock(LOCK_CANVAS_USAGE, rect, &bits); + + if (status) return JNI_FALSE; + if (!bits) { + buffer->unlock(); + return JNI_FALSE; + } + + ssize_t bytesCount = buffer->getStride() * bytesPerPixel(buffer->getPixelFormat()); + + SkBitmap bitmap; + bitmap.setInfo(SkImageInfo::Make(buffer->getWidth(), buffer->getHeight(), + convertPixelFormat(buffer->getPixelFormat()), + kPremul_SkAlphaType, + GraphicsJNI::defaultColorSpace()), + bytesCount); + + if (buffer->getWidth() > 0 && buffer->getHeight() > 0) { + bitmap.setPixels(bits); + } else { + bitmap.setPixels(NULL); + } + + Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas); + nativeCanvas->setBitmap(bitmap); + nativeCanvas->clipRect(rect.left, rect.top, rect.right, rect.bottom, + SkClipOp::kIntersect); + + if (dirtyRect) { + INVOKEV(dirtyRect, gRectClassInfo.set, + int(rect.left), int(rect.top), int(rect.right), int(rect.bottom)); + } + + return JNI_TRUE; +} + +static jboolean android_graphics_GraphicBuffer_unlockCanvasAndPost(JNIEnv* env, jobject, + jlong wrapperHandle, jobject canvas) { + + GraphicBufferWrapper* wrapper = + reinterpret_cast(wrapperHandle); + Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas); + nativeCanvas->setBitmap(SkBitmap()); + + if (wrapper) { + status_t status = wrapper->buffer->unlock(); + return status == 0 ? JNI_TRUE : JNI_FALSE; + } + + return JNI_FALSE; +} + +// ---------------------------------------------------------------------------- +// Serialization +// ---------------------------------------------------------------------------- + +static void android_graphics_GraphicBuffer_write(JNIEnv* env, jobject clazz, + jlong wrapperHandle, jobject dest) { + GraphicBufferWrapper* wrapper = + reinterpret_cast(wrapperHandle); + Parcel* parcel = parcelForJavaObject(env, dest); + if (parcel) { + parcel->write(*wrapper->buffer); + } +} + +static jlong android_graphics_GraphicBuffer_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; +} + +// ---------------------------------------------------------------------------- +// External helpers +// ---------------------------------------------------------------------------- + +sp graphicBufferForJavaObject(JNIEnv* env, jobject obj) { + if (obj) { + jlong nativeObject = env->GetLongField(obj, gGraphicBufferClassInfo.mNativeObject); + GraphicBufferWrapper* wrapper = (GraphicBufferWrapper*) nativeObject; + if (wrapper != NULL) { + sp buffer(wrapper->buffer); + return buffer; + } + } + return NULL; +} +}; + +using namespace android; +// ---------------------------------------------------------------------------- +// JNI Glue +// ---------------------------------------------------------------------------- + +const char* const kClassPathName = "android/graphics/GraphicBuffer"; + +static const JNINativeMethod gMethods[] = { + { "nCreateGraphicBuffer", "(IIII)J", (void*) android_graphics_GraphicBuffer_create }, + { "nDestroyGraphicBuffer", "(J)V", (void*) android_graphics_GraphicBuffer_destroy }, + + { "nWriteGraphicBufferToParcel", "(JLandroid/os/Parcel;)V", + (void*) android_graphics_GraphicBuffer_write }, + { "nReadGraphicBufferFromParcel", "(Landroid/os/Parcel;)J", + (void*) android_graphics_GraphicBuffer_read }, + + { "nLockCanvas", "(JLandroid/graphics/Canvas;Landroid/graphics/Rect;)Z", + (void*) android_graphics_GraphicBuffer_lockCanvas }, + { "nUnlockCanvasAndPost", "(JLandroid/graphics/Canvas;)Z", + (void*) android_graphics_GraphicBuffer_unlockCanvasAndPost } +}; + +int register_android_graphics_GraphicBuffer(JNIEnv* env) { + jclass clazz = FindClassOrDie(env, "android/graphics/GraphicBuffer"); + gGraphicBufferClassInfo.mNativeObject = GetFieldIDOrDie(env, clazz, "mNativeObject", "J"); + + clazz = FindClassOrDie(env, "android/graphics/Rect"); + gRectClassInfo.set = GetMethodIDOrDie(env, clazz, "set", "(IIII)V"); + gRectClassInfo.left = GetFieldIDOrDie(env, clazz, "left", "I"); + gRectClassInfo.top = GetFieldIDOrDie(env, clazz, "top", "I"); + gRectClassInfo.right = GetFieldIDOrDie(env, clazz, "right", "I"); + gRectClassInfo.bottom = GetFieldIDOrDie(env, clazz, "bottom", "I"); + + return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods)); +} \ No newline at end of file diff --git a/core/jni/android/graphics/GraphicBuffer.h b/core/jni/android/graphics/GraphicBuffer.h new file mode 100644 index 000000000000..509587cc4e20 --- /dev/null +++ b/core/jni/android/graphics/GraphicBuffer.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2013 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 + +#include "jni.h" + +namespace android { + +// This function does not perform any type checking, the specified +// object must be an instance of android.view.GraphicBuffer +extern sp graphicBufferForJavaObject(JNIEnv* env, jobject obj); + +} diff --git a/core/jni/android_view_GraphicBuffer.cpp b/core/jni/android_view_GraphicBuffer.cpp deleted file mode 100644 index f18837f2f72a..000000000000 --- a/core/jni/android_view_GraphicBuffer.cpp +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright (C) 2013 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 "GraphicBuffer" - -#include "jni.h" -#include "JNIHelp.h" - -#include "android_os_Parcel.h" -#include "android_view_GraphicBuffer.h" -#include "android/graphics/GraphicsJNI.h" -#include "Bitmap.h" - -#include - -#include - -#include -#include - -#include -#include -#include - -#include -#include - -#include - -#include "core_jni_helpers.h" - -namespace android { - -// ---------------------------------------------------------------------------- -// Defines -// ---------------------------------------------------------------------------- - -// Debug -static const bool kDebugGraphicBuffer = false; - -#define LOCK_CANVAS_USAGE (GraphicBuffer::USAGE_SW_READ_OFTEN | GraphicBuffer::USAGE_SW_WRITE_OFTEN) - -// ---------------------------------------------------------------------------- -// JNI Helpers -// ---------------------------------------------------------------------------- - -static struct { - jfieldID mNativeObject; -} gGraphicBufferClassInfo; - -static struct { - jmethodID set; - jfieldID left; - jfieldID top; - jfieldID right; - jfieldID bottom; -} gRectClassInfo; - -#define GET_INT(object, field) \ - env->GetIntField(object, field) - -#define SET_INT(object, field, value) \ - env->SetIntField(object, field, value) - -#define GET_LONG(object, field) \ - env->GetLongField(object, field) - -#define SET_LONG(object, field, value) \ - env->SetLongField(object, field, value) - -#define INVOKEV(object, method, ...) \ - env->CallVoidMethod(object, method, __VA_ARGS__) - -// ---------------------------------------------------------------------------- -// Types -// ---------------------------------------------------------------------------- - -class GraphicBufferWrapper { -public: - explicit GraphicBufferWrapper(const sp& buffer): buffer(buffer) { - } - - sp buffer; -}; - -// ---------------------------------------------------------------------------- -// GraphicBuffer lifecycle -// ---------------------------------------------------------------------------- - -static jlong android_view_GraphiceBuffer_create(JNIEnv* env, jobject clazz, - jint width, jint height, jint format, jint usage) { - - sp composer(ComposerService::getComposerService()); - sp alloc(composer->createGraphicBufferAlloc()); - if (alloc == NULL) { - if (kDebugGraphicBuffer) { - ALOGW("createGraphicBufferAlloc() failed in GraphicBuffer.create()"); - } - return NULL; - } - - status_t error; - sp buffer(alloc->createGraphicBuffer(width, height, format, 1, usage, &error)); - if (buffer == NULL) { - if (kDebugGraphicBuffer) { - ALOGW("createGraphicBuffer() failed in GraphicBuffer.create()"); - } - return NULL; - } - - GraphicBufferWrapper* wrapper = new GraphicBufferWrapper(buffer); - return reinterpret_cast(wrapper); -} - -static void android_view_GraphiceBuffer_destroy(JNIEnv* env, jobject clazz, - jlong wrapperHandle) { - GraphicBufferWrapper* wrapper = - reinterpret_cast(wrapperHandle); - delete wrapper; -} - -// ---------------------------------------------------------------------------- -// Canvas management -// ---------------------------------------------------------------------------- - -static inline SkColorType convertPixelFormat(int32_t format) { - switch (format) { - case PIXEL_FORMAT_RGBA_8888: - return kN32_SkColorType; - case PIXEL_FORMAT_RGBX_8888: - return kN32_SkColorType; - case PIXEL_FORMAT_RGBA_FP16: - return kRGBA_F16_SkColorType; - case PIXEL_FORMAT_RGB_565: - return kRGB_565_SkColorType; - default: - return kUnknown_SkColorType; - } -} - -static jboolean android_view_GraphicBuffer_lockCanvas(JNIEnv* env, jobject, - jlong wrapperHandle, jobject canvas, jobject dirtyRect) { - - GraphicBufferWrapper* wrapper = - reinterpret_cast(wrapperHandle); - if (!wrapper) { - return JNI_FALSE; - } - - sp buffer(wrapper->buffer); - - Rect rect(Rect::EMPTY_RECT); - if (dirtyRect) { - rect.left = GET_INT(dirtyRect, gRectClassInfo.left); - rect.top = GET_INT(dirtyRect, gRectClassInfo.top); - rect.right = GET_INT(dirtyRect, gRectClassInfo.right); - rect.bottom = GET_INT(dirtyRect, gRectClassInfo.bottom); - } else { - rect.set(Rect(buffer->getWidth(), buffer->getHeight())); - } - - void* bits = NULL; - status_t status = buffer->lock(LOCK_CANVAS_USAGE, rect, &bits); - - if (status) return JNI_FALSE; - if (!bits) { - buffer->unlock(); - return JNI_FALSE; - } - - ssize_t bytesCount = buffer->getStride() * bytesPerPixel(buffer->getPixelFormat()); - - SkBitmap bitmap; - bitmap.setInfo(SkImageInfo::Make(buffer->getWidth(), buffer->getHeight(), - convertPixelFormat(buffer->getPixelFormat()), - kPremul_SkAlphaType, - GraphicsJNI::defaultColorSpace()), - bytesCount); - - if (buffer->getWidth() > 0 && buffer->getHeight() > 0) { - bitmap.setPixels(bits); - } else { - bitmap.setPixels(NULL); - } - - Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas); - nativeCanvas->setBitmap(bitmap); - nativeCanvas->clipRect(rect.left, rect.top, rect.right, rect.bottom, - SkClipOp::kIntersect); - - if (dirtyRect) { - INVOKEV(dirtyRect, gRectClassInfo.set, - int(rect.left), int(rect.top), int(rect.right), int(rect.bottom)); - } - - return JNI_TRUE; -} - -static jboolean android_view_GraphicBuffer_unlockCanvasAndPost(JNIEnv* env, jobject, - jlong wrapperHandle, jobject canvas) { - - GraphicBufferWrapper* wrapper = - reinterpret_cast(wrapperHandle); - Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas); - nativeCanvas->setBitmap(SkBitmap()); - - if (wrapper) { - status_t status = wrapper->buffer->unlock(); - return status == 0 ? JNI_TRUE : JNI_FALSE; - } - - return JNI_FALSE; -} - -// ---------------------------------------------------------------------------- -// Serialization -// ---------------------------------------------------------------------------- - -static void android_view_GraphiceBuffer_write(JNIEnv* env, jobject clazz, - jlong wrapperHandle, jobject dest) { - GraphicBufferWrapper* wrapper = - reinterpret_cast(wrapperHandle); - Parcel* parcel = parcelForJavaObject(env, dest); - if (parcel) { - parcel->write(*wrapper->buffer); - } -} - -static jlong android_view_GraphiceBuffer_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; -} - -static jobject android_view_GraphicBuffer_createHardwareBitmap(JNIEnv* env, jobject, - jlong wrapperHandle) { - GraphicBufferWrapper* wrapper = reinterpret_cast(wrapperHandle); - sk_sp bitmap = Bitmap::createFrom(wrapper->buffer); - if (!bitmap.get()) { - ALOGW("failed to create hardware bitmap from graphic buffer"); - return NULL; - } - return bitmap::createBitmap(env, bitmap.release(), android::bitmap::kBitmapCreateFlag_None); -} - -// ---------------------------------------------------------------------------- -// External helpers -// ---------------------------------------------------------------------------- - -sp graphicBufferForJavaObject(JNIEnv* env, jobject obj) { - if (obj) { - jlong nativeObject = env->GetLongField(obj, gGraphicBufferClassInfo.mNativeObject); - GraphicBufferWrapper* wrapper = (GraphicBufferWrapper*) nativeObject; - if (wrapper != NULL) { - sp buffer(wrapper->buffer); - return buffer; - } - } - return NULL; -} - -// ---------------------------------------------------------------------------- -// JNI Glue -// ---------------------------------------------------------------------------- - -const char* const kClassPathName = "android/view/GraphicBuffer"; - -static const JNINativeMethod gMethods[] = { - { "nCreateGraphicBuffer", "(IIII)J", (void*) android_view_GraphiceBuffer_create }, - { "nDestroyGraphicBuffer", "(J)V", (void*) android_view_GraphiceBuffer_destroy }, - - { "nWriteGraphicBufferToParcel", "(JLandroid/os/Parcel;)V", - (void*) android_view_GraphiceBuffer_write }, - { "nReadGraphicBufferFromParcel", "(Landroid/os/Parcel;)J", - (void*) android_view_GraphiceBuffer_read }, - - { "nLockCanvas", "(JLandroid/graphics/Canvas;Landroid/graphics/Rect;)Z", - (void*) android_view_GraphicBuffer_lockCanvas }, - { "nUnlockCanvasAndPost", "(JLandroid/graphics/Canvas;)Z", - (void*) android_view_GraphicBuffer_unlockCanvasAndPost }, - { "nCreateHardwareBitmap", "(J)Landroid/graphics/Bitmap;", - (void*) android_view_GraphicBuffer_createHardwareBitmap - } -}; - -int register_android_view_GraphicBuffer(JNIEnv* env) { - jclass clazz = FindClassOrDie(env, "android/view/GraphicBuffer"); - gGraphicBufferClassInfo.mNativeObject = GetFieldIDOrDie(env, clazz, "mNativeObject", "J"); - - clazz = FindClassOrDie(env, "android/graphics/Rect"); - gRectClassInfo.set = GetMethodIDOrDie(env, clazz, "set", "(IIII)V"); - gRectClassInfo.left = GetFieldIDOrDie(env, clazz, "left", "I"); - gRectClassInfo.top = GetFieldIDOrDie(env, clazz, "top", "I"); - gRectClassInfo.right = GetFieldIDOrDie(env, clazz, "right", "I"); - gRectClassInfo.bottom = GetFieldIDOrDie(env, clazz, "bottom", "I"); - - return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods)); -} - -}; diff --git a/core/jni/android_view_GraphicBuffer.h b/core/jni/android_view_GraphicBuffer.h deleted file mode 100644 index 509587cc4e20..000000000000 --- a/core/jni/android_view_GraphicBuffer.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2013 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 - -#include "jni.h" - -namespace android { - -// This function does not perform any type checking, the specified -// object must be an instance of android.view.GraphicBuffer -extern sp graphicBufferForJavaObject(JNIEnv* env, jobject obj); - -} diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 14dcb3febe6f..c00bcd461181 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -36,7 +36,6 @@ #include #include -#include "android_view_GraphicBuffer.h" #include "android_os_MessageQueue.h" #include diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index a259937c0b73..f58ff675d63b 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -654,6 +654,17 @@ public final class Bitmap implements Parcelable { return b; } + /** + * Create hardware bitmap backed GraphicBuffer. + * + * @return Bitmap or null if this GraphicBuffer has unsupported PixelFormat. + * currently PIXEL_FORMAT_RGBA_8888 is the only supported format + * @hide + */ + public static Bitmap createHardwareBitmap(GraphicBuffer graphicBuffer) { + return nativeCreateHardwareBitmap(graphicBuffer); + } + /** * 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 @@ -1794,4 +1805,5 @@ public final class Bitmap implements Parcelable { private static native void nativePrepareToDraw(long nativeBitmap); private static native int nativeGetAllocationByteCount(long nativeBitmap); private static native Bitmap nativeCopyPreserveInternalConfig(long nativeBitmap); + private static native Bitmap nativeCreateHardwareBitmap(GraphicBuffer buffer); } diff --git a/graphics/java/android/graphics/GraphicBuffer.aidl b/graphics/java/android/graphics/GraphicBuffer.aidl new file mode 100644 index 000000000000..134699aa3e0c --- /dev/null +++ b/graphics/java/android/graphics/GraphicBuffer.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2013 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; + +parcelable GraphicBuffer; diff --git a/graphics/java/android/graphics/GraphicBuffer.java b/graphics/java/android/graphics/GraphicBuffer.java new file mode 100644 index 000000000000..3be9216177e9 --- /dev/null +++ b/graphics/java/android/graphics/GraphicBuffer.java @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2013 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.os.Parcel; +import android.os.Parcelable; + +/** + * Simple wrapper for the native GraphicBuffer class. + * + * @hide + */ +@SuppressWarnings("UnusedDeclaration") +public class GraphicBuffer implements Parcelable { + // Note: keep usage flags in sync with GraphicBuffer.h and gralloc.h + public static final int USAGE_SW_READ_NEVER = 0x0; + public static final int USAGE_SW_READ_RARELY = 0x2; + public static final int USAGE_SW_READ_OFTEN = 0x3; + public static final int USAGE_SW_READ_MASK = 0xF; + + public static final int USAGE_SW_WRITE_NEVER = 0x0; + public static final int USAGE_SW_WRITE_RARELY = 0x20; + public static final int USAGE_SW_WRITE_OFTEN = 0x30; + public static final int USAGE_SW_WRITE_MASK = 0xF0; + + public static final int USAGE_SOFTWARE_MASK = USAGE_SW_READ_MASK | USAGE_SW_WRITE_MASK; + + public static final int USAGE_PROTECTED = 0x4000; + + public static final int USAGE_HW_TEXTURE = 0x100; + public static final int USAGE_HW_RENDER = 0x200; + public static final int USAGE_HW_2D = 0x400; + public static final int USAGE_HW_COMPOSER = 0x800; + public static final int USAGE_HW_VIDEO_ENCODER = 0x10000; + public static final int USAGE_HW_MASK = 0x71F00; + + private final int mWidth; + private final int mHeight; + private final int mFormat; + private final int mUsage; + // Note: do not rename, this field is used by native code + private final long mNativeObject; + + // These two fields are only used by lock/unlockCanvas() + private Canvas mCanvas; + private int mSaveCount; + + // If set to true, this GraphicBuffer instance cannot be used anymore + private boolean mDestroyed; + + /** + * Creates new GraphicBuffer instance. This method will return null + * if the buffer cannot be created. + * + * @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 as specified in {@link PixelFormat} + * @param usage Hint indicating how the buffer will be used + * + * @return A GraphicBuffer instance or null + */ + public static GraphicBuffer create(int width, int height, int format, int usage) { + long nativeObject = nCreateGraphicBuffer(width, height, format, usage); + if (nativeObject != 0) { + return new GraphicBuffer(width, height, format, usage, nativeObject); + } + return null; + } + + /** + * Private use only. See {@link #create(int, int, int, int)}. + */ + private GraphicBuffer(int width, int height, int format, int usage, long nativeObject) { + mWidth = width; + mHeight = height; + mFormat = format; + mUsage = usage; + mNativeObject = nativeObject; + } + + /** + * Returns the width of this buffer in pixels. + */ + public int getWidth() { + return mWidth; + } + + /** + * Returns the height of this buffer in pixels. + */ + public int getHeight() { + return mHeight; + } + + /** + * Returns the pixel format of this buffer. The pixel format must be one of + * the formats defined in {@link PixelFormat}. + */ + public int getFormat() { + return mFormat; + } + + /** + * Returns the usage hint set on this buffer. + */ + public int getUsage() { + return mUsage; + } + + /** + *

Start editing the pixels in the buffer. A null is returned if the buffer + * cannot be locked for editing.

+ * + *

The content of the buffer is preserved between unlockCanvas() + * and lockCanvas().

+ * + *

If this method is called after {@link #destroy()}, the return value will + * always be null.

+ * + * @return A Canvas used to draw into the buffer, or null. + * + * @see #lockCanvas(android.graphics.Rect) + * @see #unlockCanvasAndPost(android.graphics.Canvas) + * @see #isDestroyed() + */ + public Canvas lockCanvas() { + return lockCanvas(null); + } + + /** + * Just like {@link #lockCanvas()} but allows specification of a dirty + * rectangle. + * + *

If this method is called after {@link #destroy()}, the return value will + * always be null.

+ * + * @param dirty Area of the buffer that may be modified. + + * @return A Canvas used to draw into the surface, or null. + * + * @see #lockCanvas() + * @see #unlockCanvasAndPost(android.graphics.Canvas) + * @see #isDestroyed() + */ + public Canvas lockCanvas(Rect dirty) { + if (mDestroyed) { + return null; + } + + if (mCanvas == null) { + mCanvas = new Canvas(); + } + + if (nLockCanvas(mNativeObject, mCanvas, dirty)) { + mSaveCount = mCanvas.save(); + return mCanvas; + } + + return null; + } + + /** + * Finish editing pixels in the buffer. + * + *

This method doesn't do anything if {@link #destroy()} was + * previously called.

+ * + * @param canvas The Canvas previously returned by lockCanvas() + * + * @see #lockCanvas() + * @see #lockCanvas(android.graphics.Rect) + * @see #isDestroyed() + */ + public void unlockCanvasAndPost(Canvas canvas) { + if (!mDestroyed && mCanvas != null && canvas == mCanvas) { + canvas.restoreToCount(mSaveCount); + mSaveCount = 0; + + nUnlockCanvasAndPost(mNativeObject, mCanvas); + } + } + + /** + * Destroyes 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 ({@link #lockCanvas()} must not be called, + * etc.) + * + * @see #isDestroyed() + */ + public void destroy() { + if (!mDestroyed) { + mDestroyed = true; + nDestroyGraphicBuffer(mNativeObject); + } + } + + /** + * Indicates whether this buffer has been destroyed. A destroyed buffer + * cannot be used in any way: locking a Canvas will return null, the buffer + * cannot be written to a parcel, etc. + * + * @return True if this GraphicBuffer is in a destroyed state, + * false otherwise. + * + * @see #destroy() + */ + public boolean isDestroyed() { + return mDestroyed; + } + + @Override + protected void finalize() throws Throwable { + try { + if (!mDestroyed) nDestroyGraphicBuffer(mNativeObject); + } finally { + super.finalize(); + } + } + + @Override + public int describeContents() { + return 0; + } + + /** + * 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 (mDestroyed) { + throw new IllegalStateException("This GraphicBuffer has been destroyed and cannot be " + + "written to a parcel."); + } + + dest.writeInt(mWidth); + dest.writeInt(mHeight); + dest.writeInt(mFormat); + dest.writeInt(mUsage); + nWriteGraphicBufferToParcel(mNativeObject, dest); + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public GraphicBuffer createFromParcel(Parcel in) { + int width = in.readInt(); + int height = in.readInt(); + int format = in.readInt(); + int usage = in.readInt(); + long nativeObject = nReadGraphicBufferFromParcel(in); + if (nativeObject != 0) { + return new GraphicBuffer(width, height, format, usage, nativeObject); + } + return null; + } + + public GraphicBuffer[] newArray(int size) { + return new GraphicBuffer[size]; + } + }; + + private static native long nCreateGraphicBuffer(int width, int height, int format, int usage); + private static native void nDestroyGraphicBuffer(long nativeObject); + private static native void nWriteGraphicBufferToParcel(long nativeObject, Parcel dest); + private static native long nReadGraphicBufferFromParcel(Parcel in); + private static native boolean nLockCanvas(long nativeObject, Canvas canvas, Rect dirty); + private static native boolean nUnlockCanvasAndPost(long nativeObject, Canvas canvas); +} -- cgit v1.2.3-59-g8ed1b From 6e3658a63843096058ed444d073fbcd191fd7e1b Mon Sep 17 00:00:00 2001 From: sergeyv Date: Wed, 4 Jan 2017 16:57:51 -0800 Subject: Hidden method to get a graphic buffer from a hardware bitmap Test: locally tested Bitmap.getGraphicBuffer() bug:30999911 Change-Id: I68d56d769045bada6a5db90ed884a570c49be4fd --- core/jni/android/graphics/Bitmap.cpp | 18 +++++++++++++++--- core/jni/android/graphics/GraphicBuffer.cpp | 20 +++++++++++++++++--- core/jni/android/graphics/GraphicBuffer.h | 2 ++ graphics/java/android/graphics/Bitmap.java | 10 ++++++++++ 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index bea2b8c53e2f..2bde9911da8e 100755 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -1292,7 +1292,7 @@ static jint Bitmap_getAllocationByteCount(JNIEnv* env, jobject, jlong bitmapPtr) return static_cast(bitmapHandle->getAllocationByteCount()); } -static jobject Bitmap_nativeCopyPreserveInternalConfig(JNIEnv* env, jobject, jlong bitmapPtr) { +static jobject Bitmap_copyPreserveInternalConfig(JNIEnv* env, jobject, jlong bitmapPtr) { LocalScopedBitmap bitmapHandle(bitmapPtr); LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(), "Hardware config is only supported config in Bitmap_nativeCopyPreserveInternalConfig"); @@ -1319,6 +1319,16 @@ static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphic return bitmap::createBitmap(env, bitmap.release(), android::bitmap::kBitmapCreateFlag_None); } +static jobject Bitmap_createGraphicBufferHandle(JNIEnv* env, jobject, jlong bitmapPtr) { + LocalScopedBitmap bitmapHandle(bitmapPtr); + LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(), + "Hardware config is only supported config in Bitmap_getGraphicBuffer"); + + Bitmap& hwuiBitmap = bitmapHandle->bitmap(); + sp buffer(hwuiBitmap.graphicBuffer()); + return createJavaGraphicBuffer(env, buffer); +} + /////////////////////////////////////////////////////////////////////////////// static jclass make_globalref(JNIEnv* env, const char classname[]) { @@ -1378,9 +1388,11 @@ static const JNINativeMethod gBitmapMethods[] = { { "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw }, { "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount }, { "nativeCopyPreserveInternalConfig", "(J)Landroid/graphics/Bitmap;", - (void*)Bitmap_nativeCopyPreserveInternalConfig }, + (void*)Bitmap_copyPreserveInternalConfig }, { "nativeCreateHardwareBitmap", "(Landroid/graphics/GraphicBuffer;)Landroid/graphics/Bitmap;", - (void*) Bitmap_createHardwareBitmap } + (void*) Bitmap_createHardwareBitmap }, + { "nativeCreateGraphicBufferHandle", "(J)Landroid/graphics/GraphicBuffer;", + (void*) Bitmap_createGraphicBufferHandle } }; int register_android_graphics_Bitmap(JNIEnv* env) diff --git a/core/jni/android/graphics/GraphicBuffer.cpp b/core/jni/android/graphics/GraphicBuffer.cpp index 6cc710964050..c61b53e5fa65 100644 --- a/core/jni/android/graphics/GraphicBuffer.cpp +++ b/core/jni/android/graphics/GraphicBuffer.cpp @@ -58,6 +58,8 @@ static const bool kDebugGraphicBuffer = false; static struct { jfieldID mNativeObject; + jclass mClass; + jmethodID mConstructorMethodID; } gGraphicBufferClassInfo; static struct { @@ -266,6 +268,15 @@ sp graphicBufferForJavaObject(JNIEnv* env, jobject obj) { } return NULL; } + +jobject createJavaGraphicBuffer(JNIEnv* env, const sp& buffer) { + GraphicBufferWrapper* wrapper = new GraphicBufferWrapper(buffer); + jobject obj = env->NewObject(gGraphicBufferClassInfo.mClass, + gGraphicBufferClassInfo.mConstructorMethodID, buffer->getWidth(), buffer->getHeight(), + buffer->getPixelFormat(), buffer->getUsage(), reinterpret_cast(wrapper)); + return obj; +} + }; using namespace android; @@ -291,10 +302,13 @@ static const JNINativeMethod gMethods[] = { }; int register_android_graphics_GraphicBuffer(JNIEnv* env) { - jclass clazz = FindClassOrDie(env, "android/graphics/GraphicBuffer"); - gGraphicBufferClassInfo.mNativeObject = GetFieldIDOrDie(env, clazz, "mNativeObject", "J"); + gGraphicBufferClassInfo.mClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, kClassPathName)); + gGraphicBufferClassInfo.mNativeObject = GetFieldIDOrDie(env, gGraphicBufferClassInfo.mClass, + "mNativeObject", "J"); + gGraphicBufferClassInfo.mConstructorMethodID = env->GetMethodID(gGraphicBufferClassInfo.mClass, + "", "(IIIIJ)V"); - clazz = FindClassOrDie(env, "android/graphics/Rect"); + jclass clazz = FindClassOrDie(env, "android/graphics/Rect"); gRectClassInfo.set = GetMethodIDOrDie(env, clazz, "set", "(IIII)V"); gRectClassInfo.left = GetFieldIDOrDie(env, clazz, "left", "I"); gRectClassInfo.top = GetFieldIDOrDie(env, clazz, "top", "I"); diff --git a/core/jni/android/graphics/GraphicBuffer.h b/core/jni/android/graphics/GraphicBuffer.h index 509587cc4e20..0d7266942748 100644 --- a/core/jni/android/graphics/GraphicBuffer.h +++ b/core/jni/android/graphics/GraphicBuffer.h @@ -24,4 +24,6 @@ namespace android { // object must be an instance of android.view.GraphicBuffer extern sp graphicBufferForJavaObject(JNIEnv* env, jobject obj); +jobject createJavaGraphicBuffer(JNIEnv* env, const sp& buffer); + } diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index f58ff675d63b..ba7f05d86fc8 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -1746,6 +1746,15 @@ public final class Bitmap implements Parcelable { nativePrepareToDraw(mNativePtr); } + /** + * + * @return {@link GraphicBuffer} which is internally used by hardware bitmap + * @hide + */ + public GraphicBuffer createGraphicBufferHandle() { + return nativeCreateGraphicBufferHandle(mNativePtr); + } + //////////// native methods private static native Bitmap nativeCreate(int[] colors, int offset, @@ -1806,4 +1815,5 @@ 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 GraphicBuffer nativeCreateGraphicBufferHandle(long nativeBitmap); } -- cgit v1.2.3-59-g8ed1b