1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "GraphicBuffer" 18 19 #include "jni.h" 20 #include "JNIHelp.h" 21 22 #include "android_os_Parcel.h" 23 #include "android_view_GraphicBuffer.h" 24 #include "android/graphics/GraphicsJNI.h" 25 26 #include <android_runtime/AndroidRuntime.h> 27 28 #include <binder/Parcel.h> 29 30 #include <ui/GraphicBuffer.h> 31 #include <ui/PixelFormat.h> 32 33 #include <gui/IGraphicBufferAlloc.h> 34 #include <gui/ISurfaceComposer.h> 35 36 #include <SkCanvas.h> 37 #include <SkBitmap.h> 38 39 #include <private/gui/ComposerService.h> 40 41 #include "core_jni_helpers.h" 42 43 namespace android { 44 45 // ---------------------------------------------------------------------------- 46 // Defines 47 // ---------------------------------------------------------------------------- 48 49 // Debug 50 static const bool kDebugGraphicBuffer = false; 51 52 #define LOCK_CANVAS_USAGE GraphicBuffer::USAGE_SW_READ_OFTEN | GraphicBuffer::USAGE_SW_WRITE_OFTEN 53 54 // ---------------------------------------------------------------------------- 55 // JNI Helpers 56 // ---------------------------------------------------------------------------- 57 58 static struct { 59 jfieldID mNativeObject; 60 } gGraphicBufferClassInfo; 61 62 static struct { 63 jmethodID set; 64 jfieldID left; 65 jfieldID top; 66 jfieldID right; 67 jfieldID bottom; 68 } gRectClassInfo; 69 70 #define GET_INT(object, field) \ 71 env->GetIntField(object, field) 72 73 #define SET_INT(object, field, value) \ 74 env->SetIntField(object, field, value) 75 76 #define GET_LONG(object, field) \ 77 env->GetLongField(object, field) 78 79 #define SET_LONG(object, field, value) \ 80 env->SetLongField(object, field, value) 81 82 #define INVOKEV(object, method, ...) \ 83 env->CallVoidMethod(object, method, __VA_ARGS__) 84 85 // ---------------------------------------------------------------------------- 86 // Types 87 // ---------------------------------------------------------------------------- 88 89 class GraphicBufferWrapper { 90 public: 91 GraphicBufferWrapper(const sp<GraphicBuffer>& buffer): buffer(buffer) { 92 } 93 94 sp<GraphicBuffer> buffer; 95 }; 96 97 // ---------------------------------------------------------------------------- 98 // GraphicBuffer lifecycle 99 // ---------------------------------------------------------------------------- 100 101 static jlong android_view_GraphiceBuffer_create(JNIEnv* env, jobject clazz, 102 jint width, jint height, jint format, jint usage) { 103 104 sp<ISurfaceComposer> composer(ComposerService::getComposerService()); 105 sp<IGraphicBufferAlloc> alloc(composer->createGraphicBufferAlloc()); 106 if (alloc == NULL) { 107 if (kDebugGraphicBuffer) { 108 ALOGW("createGraphicBufferAlloc() failed in GraphicBuffer.create()"); 109 } 110 return NULL; 111 } 112 113 status_t error; 114 sp<GraphicBuffer> buffer(alloc->createGraphicBuffer(width, height, format, usage, &error)); 115 if (buffer == NULL) { 116 if (kDebugGraphicBuffer) { 117 ALOGW("createGraphicBuffer() failed in GraphicBuffer.create()"); 118 } 119 return NULL; 120 } 121 122 GraphicBufferWrapper* wrapper = new GraphicBufferWrapper(buffer); 123 return reinterpret_cast<jlong>(wrapper); 124 } 125 126 static void android_view_GraphiceBuffer_destroy(JNIEnv* env, jobject clazz, 127 jlong wrapperHandle) { 128 GraphicBufferWrapper* wrapper = 129 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle); 130 delete wrapper; 131 } 132 133 // ---------------------------------------------------------------------------- 134 // Canvas management 135 // ---------------------------------------------------------------------------- 136 137 static inline SkColorType convertPixelFormat(int32_t format) { 138 switch (format) { 139 case PIXEL_FORMAT_RGBA_8888: 140 return kN32_SkColorType; 141 case PIXEL_FORMAT_RGBX_8888: 142 return kN32_SkColorType; 143 case PIXEL_FORMAT_RGB_565: 144 return kRGB_565_SkColorType; 145 default: 146 return kUnknown_SkColorType; 147 } 148 } 149 150 static jboolean android_view_GraphicBuffer_lockCanvas(JNIEnv* env, jobject, 151 jlong wrapperHandle, jobject canvas, jobject dirtyRect) { 152 153 GraphicBufferWrapper* wrapper = 154 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle); 155 if (!wrapper) { 156 return JNI_FALSE; 157 } 158 159 sp<GraphicBuffer> buffer(wrapper->buffer); 160 161 Rect rect(Rect::EMPTY_RECT); 162 if (dirtyRect) { 163 rect.left = GET_INT(dirtyRect, gRectClassInfo.left); 164 rect.top = GET_INT(dirtyRect, gRectClassInfo.top); 165 rect.right = GET_INT(dirtyRect, gRectClassInfo.right); 166 rect.bottom = GET_INT(dirtyRect, gRectClassInfo.bottom); 167 } else { 168 rect.set(Rect(buffer->getWidth(), buffer->getHeight())); 169 } 170 171 void* bits = NULL; 172 status_t status = buffer->lock(LOCK_CANVAS_USAGE, rect, &bits); 173 174 if (status) return JNI_FALSE; 175 if (!bits) { 176 buffer->unlock(); 177 return JNI_FALSE; 178 } 179 180 ssize_t bytesCount = buffer->getStride() * bytesPerPixel(buffer->getPixelFormat()); 181 182 SkBitmap bitmap; 183 bitmap.setInfo(SkImageInfo::Make(buffer->getWidth(), buffer->getHeight(), 184 convertPixelFormat(buffer->getPixelFormat()), 185 kPremul_SkAlphaType), 186 bytesCount); 187 188 if (buffer->getWidth() > 0 && buffer->getHeight() > 0) { 189 bitmap.setPixels(bits); 190 } else { 191 bitmap.setPixels(NULL); 192 } 193 194 Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas); 195 nativeCanvas->setBitmap(bitmap); 196 nativeCanvas->clipRect(rect.left, rect.top, rect.right, rect.bottom); 197 198 if (dirtyRect) { 199 INVOKEV(dirtyRect, gRectClassInfo.set, 200 int(rect.left), int(rect.top), int(rect.right), int(rect.bottom)); 201 } 202 203 return JNI_TRUE; 204 } 205 206 static jboolean android_view_GraphicBuffer_unlockCanvasAndPost(JNIEnv* env, jobject, 207 jlong wrapperHandle, jobject canvas) { 208 209 GraphicBufferWrapper* wrapper = 210 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle); 211 Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas); 212 nativeCanvas->setBitmap(SkBitmap()); 213 214 if (wrapper) { 215 status_t status = wrapper->buffer->unlock(); 216 return status == 0 ? JNI_TRUE : JNI_FALSE; 217 } 218 219 return JNI_FALSE; 220 } 221 222 // ---------------------------------------------------------------------------- 223 // Serialization 224 // ---------------------------------------------------------------------------- 225 226 static void android_view_GraphiceBuffer_write(JNIEnv* env, jobject clazz, 227 jlong wrapperHandle, jobject dest) { 228 GraphicBufferWrapper* wrapper = 229 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle); 230 Parcel* parcel = parcelForJavaObject(env, dest); 231 if (parcel) { 232 parcel->write(*wrapper->buffer); 233 } 234 } 235 236 static jlong android_view_GraphiceBuffer_read(JNIEnv* env, jobject clazz, 237 jobject in) { 238 239 Parcel* parcel = parcelForJavaObject(env, in); 240 if (parcel) { 241 sp<GraphicBuffer> buffer = new GraphicBuffer(); 242 parcel->read(*buffer); 243 return reinterpret_cast<jlong>(new GraphicBufferWrapper(buffer)); 244 } 245 246 return NULL; 247 } 248 249 // ---------------------------------------------------------------------------- 250 // External helpers 251 // ---------------------------------------------------------------------------- 252 253 sp<GraphicBuffer> graphicBufferForJavaObject(JNIEnv* env, jobject obj) { 254 if (obj) { 255 jlong nativeObject = env->GetLongField(obj, gGraphicBufferClassInfo.mNativeObject); 256 GraphicBufferWrapper* wrapper = (GraphicBufferWrapper*) nativeObject; 257 if (wrapper != NULL) { 258 sp<GraphicBuffer> buffer(wrapper->buffer); 259 return buffer; 260 } 261 } 262 return NULL; 263 } 264 265 // ---------------------------------------------------------------------------- 266 // JNI Glue 267 // ---------------------------------------------------------------------------- 268 269 const char* const kClassPathName = "android/view/GraphicBuffer"; 270 271 static const JNINativeMethod gMethods[] = { 272 { "nCreateGraphicBuffer", "(IIII)J", (void*) android_view_GraphiceBuffer_create }, 273 { "nDestroyGraphicBuffer", "(J)V", (void*) android_view_GraphiceBuffer_destroy }, 274 275 { "nWriteGraphicBufferToParcel", "(JLandroid/os/Parcel;)V", 276 (void*) android_view_GraphiceBuffer_write }, 277 { "nReadGraphicBufferFromParcel", "(Landroid/os/Parcel;)J", 278 (void*) android_view_GraphiceBuffer_read }, 279 280 { "nLockCanvas", "(JLandroid/graphics/Canvas;Landroid/graphics/Rect;)Z", 281 (void*) android_view_GraphicBuffer_lockCanvas }, 282 { "nUnlockCanvasAndPost", "(JLandroid/graphics/Canvas;)Z", 283 (void*) android_view_GraphicBuffer_unlockCanvasAndPost }, 284 }; 285 286 int register_android_view_GraphicBuffer(JNIEnv* env) { 287 jclass clazz = FindClassOrDie(env, "android/view/GraphicBuffer"); 288 gGraphicBufferClassInfo.mNativeObject = GetFieldIDOrDie(env, clazz, "mNativeObject", "J"); 289 290 clazz = FindClassOrDie(env, "android/graphics/Rect"); 291 gRectClassInfo.set = GetMethodIDOrDie(env, clazz, "set", "(IIII)V"); 292 gRectClassInfo.left = GetFieldIDOrDie(env, clazz, "left", "I"); 293 gRectClassInfo.top = GetFieldIDOrDie(env, clazz, "top", "I"); 294 gRectClassInfo.right = GetFieldIDOrDie(env, clazz, "right", "I"); 295 gRectClassInfo.bottom = GetFieldIDOrDie(env, clazz, "bottom", "I"); 296 297 return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods)); 298 } 299 300 }; 301