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 25 #include <android_runtime/AndroidRuntime.h> 26 27 #include <binder/Parcel.h> 28 29 #include <ui/GraphicBuffer.h> 30 #include <ui/PixelFormat.h> 31 32 #include <gui/IGraphicBufferAlloc.h> 33 #include <gui/ISurfaceComposer.h> 34 35 #include <SkCanvas.h> 36 #include <SkBitmap.h> 37 38 #include <private/gui/ComposerService.h> 39 40 namespace android { 41 42 // ---------------------------------------------------------------------------- 43 // Defines 44 // ---------------------------------------------------------------------------- 45 46 // Debug 47 #define DEBUG_GRAPHIC_BUFFER 0 48 49 // Debug 50 #if DEBUG_GRAPHIC_BUFFER 51 #define GB_LOGD(...) ALOGD(__VA_ARGS__) 52 #define GB_LOGW(...) ALOGW(__VA_ARGS__) 53 #else 54 #define GB_LOGD(...) 55 #define GB_LOGW(...) 56 #endif 57 58 #define LOCK_CANVAS_USAGE GraphicBuffer::USAGE_SW_READ_OFTEN | GraphicBuffer::USAGE_SW_WRITE_OFTEN 59 60 // ---------------------------------------------------------------------------- 61 // JNI Helpers 62 // ---------------------------------------------------------------------------- 63 64 static struct { 65 jfieldID mNativeObject; 66 } gGraphicBufferClassInfo; 67 68 static struct { 69 jmethodID set; 70 jfieldID left; 71 jfieldID top; 72 jfieldID right; 73 jfieldID bottom; 74 } gRectClassInfo; 75 76 static struct { 77 jfieldID mFinalizer; 78 jfieldID mNativeCanvas; 79 jfieldID mSurfaceFormat; 80 } gCanvasClassInfo; 81 82 static struct { 83 jfieldID mNativeCanvas; 84 } gCanvasFinalizerClassInfo; 85 86 #define GET_INT(object, field) \ 87 env->GetIntField(object, field) 88 89 #define SET_INT(object, field, value) \ 90 env->SetIntField(object, field, value) 91 92 #define INVOKEV(object, method, ...) \ 93 env->CallVoidMethod(object, method, __VA_ARGS__) 94 95 // ---------------------------------------------------------------------------- 96 // Types 97 // ---------------------------------------------------------------------------- 98 99 class GraphicBufferWrapper { 100 public: 101 GraphicBufferWrapper(const sp<GraphicBuffer>& buffer): buffer(buffer) { 102 } 103 104 sp<GraphicBuffer> buffer; 105 }; 106 107 // ---------------------------------------------------------------------------- 108 // GraphicBuffer lifecycle 109 // ---------------------------------------------------------------------------- 110 111 static GraphicBufferWrapper* android_view_GraphiceBuffer_create(JNIEnv* env, jobject clazz, 112 jint width, jint height, jint format, jint usage) { 113 114 sp<ISurfaceComposer> composer(ComposerService::getComposerService()); 115 sp<IGraphicBufferAlloc> alloc(composer->createGraphicBufferAlloc()); 116 if (alloc == NULL) { 117 GB_LOGW("createGraphicBufferAlloc() failed in GraphicBuffer.create()"); 118 return NULL; 119 } 120 121 status_t error; 122 sp<GraphicBuffer> buffer(alloc->createGraphicBuffer(width, height, format, usage, &error)); 123 if (buffer == NULL) { 124 GB_LOGW("createGraphicBuffer() failed in GraphicBuffer.create()"); 125 return NULL; 126 } 127 128 return new GraphicBufferWrapper(buffer); 129 } 130 131 static void android_view_GraphiceBuffer_destroy(JNIEnv* env, jobject clazz, 132 GraphicBufferWrapper* wrapper) { 133 delete wrapper; 134 } 135 136 // ---------------------------------------------------------------------------- 137 // Canvas management 138 // ---------------------------------------------------------------------------- 139 140 static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) { 141 jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer); 142 SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>( 143 GET_INT(canvasObj, gCanvasClassInfo.mNativeCanvas)); 144 SET_INT(canvasObj, gCanvasClassInfo.mNativeCanvas, (int) newCanvas); 145 SET_INT(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (int) newCanvas); 146 SkSafeUnref(previousCanvas); 147 } 148 149 static inline SkBitmap::Config convertPixelFormat(int32_t format) { 150 switch (format) { 151 case PIXEL_FORMAT_RGBA_8888: 152 return SkBitmap::kARGB_8888_Config; 153 case PIXEL_FORMAT_RGBX_8888: 154 return SkBitmap::kARGB_8888_Config; 155 case PIXEL_FORMAT_RGB_565: 156 return SkBitmap::kRGB_565_Config; 157 default: 158 return SkBitmap::kNo_Config; 159 } 160 } 161 162 static jboolean android_view_GraphicBuffer_lockCanvas(JNIEnv* env, jobject, 163 GraphicBufferWrapper* wrapper, jobject canvas, jobject dirtyRect) { 164 165 if (!wrapper) { 166 return false; 167 } 168 169 sp<GraphicBuffer> buffer(wrapper->buffer); 170 171 Rect rect; 172 if (dirtyRect) { 173 rect.left = GET_INT(dirtyRect, gRectClassInfo.left); 174 rect.top = GET_INT(dirtyRect, gRectClassInfo.top); 175 rect.right = GET_INT(dirtyRect, gRectClassInfo.right); 176 rect.bottom = GET_INT(dirtyRect, gRectClassInfo.bottom); 177 } else { 178 rect.set(Rect(buffer->getWidth(), buffer->getHeight())); 179 } 180 181 void* bits = NULL; 182 status_t status = buffer->lock(LOCK_CANVAS_USAGE, rect, &bits); 183 184 if (status) return false; 185 if (!bits) { 186 buffer->unlock(); 187 return false; 188 } 189 190 ssize_t bytesCount = buffer->getStride() * bytesPerPixel(buffer->getPixelFormat()); 191 192 SkBitmap bitmap; 193 bitmap.setConfig(convertPixelFormat(buffer->getPixelFormat()), 194 buffer->getWidth(), buffer->getHeight(), bytesCount); 195 196 if (buffer->getWidth() > 0 && buffer->getHeight() > 0) { 197 bitmap.setPixels(bits); 198 } else { 199 bitmap.setPixels(NULL); 200 } 201 202 SET_INT(canvas, gCanvasClassInfo.mSurfaceFormat, buffer->getPixelFormat()); 203 204 SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap)); 205 swapCanvasPtr(env, canvas, nativeCanvas); 206 207 SkRect clipRect; 208 clipRect.set(rect.left, rect.top, rect.right, rect.bottom); 209 nativeCanvas->clipRect(clipRect); 210 211 if (dirtyRect) { 212 INVOKEV(dirtyRect, gRectClassInfo.set, 213 int(rect.left), int(rect.top), int(rect.right), int(rect.bottom)); 214 } 215 216 return true; 217 } 218 219 static jboolean android_view_GraphicBuffer_unlockCanvasAndPost(JNIEnv* env, jobject, 220 GraphicBufferWrapper* wrapper, jobject canvas) { 221 222 SkCanvas* nativeCanvas = SkNEW(SkCanvas); 223 swapCanvasPtr(env, canvas, nativeCanvas); 224 225 if (wrapper) { 226 status_t status = wrapper->buffer->unlock(); 227 return status == 0; 228 } 229 230 return false; 231 } 232 233 // ---------------------------------------------------------------------------- 234 // Serialization 235 // ---------------------------------------------------------------------------- 236 237 static void android_view_GraphiceBuffer_write(JNIEnv* env, jobject clazz, 238 GraphicBufferWrapper* wrapper, jobject dest) { 239 Parcel* parcel = parcelForJavaObject(env, dest); 240 if (parcel) { 241 parcel->write(*wrapper->buffer); 242 } 243 } 244 245 static GraphicBufferWrapper* android_view_GraphiceBuffer_read(JNIEnv* env, jobject clazz, 246 jobject in) { 247 248 Parcel* parcel = parcelForJavaObject(env, in); 249 if (parcel) { 250 sp<GraphicBuffer> buffer = new GraphicBuffer(); 251 parcel->read(*buffer); 252 return new GraphicBufferWrapper(buffer); 253 } 254 255 return NULL; 256 } 257 258 // ---------------------------------------------------------------------------- 259 // External helpers 260 // ---------------------------------------------------------------------------- 261 262 sp<GraphicBuffer> graphicBufferForJavaObject(JNIEnv* env, jobject obj) { 263 if (obj) { 264 jint nativeObject = env->GetIntField(obj, gGraphicBufferClassInfo.mNativeObject); 265 GraphicBufferWrapper* wrapper = (GraphicBufferWrapper*) nativeObject; 266 if (wrapper != NULL) { 267 sp<GraphicBuffer> buffer(wrapper->buffer); 268 return buffer; 269 } 270 } 271 return NULL; 272 } 273 274 // ---------------------------------------------------------------------------- 275 // JNI Glue 276 // ---------------------------------------------------------------------------- 277 278 #define FIND_CLASS(var, className) \ 279 var = env->FindClass(className); \ 280 LOG_FATAL_IF(! var, "Unable to find class " className); 281 282 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ 283 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ 284 LOG_FATAL_IF(! var, "Unable to find field " fieldName); 285 286 #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \ 287 var = env->GetMethodID(clazz, methodName, methodDescriptor); \ 288 LOG_FATAL_IF(!var, "Unable to find method " methodName); 289 290 const char* const kClassPathName = "android/view/GraphicBuffer"; 291 292 static JNINativeMethod gMethods[] = { 293 { "nCreateGraphicBuffer", "(IIII)I", (void*) android_view_GraphiceBuffer_create }, 294 { "nDestroyGraphicBuffer", "(I)V", (void*) android_view_GraphiceBuffer_destroy }, 295 296 { "nWriteGraphicBufferToParcel", "(ILandroid/os/Parcel;)V", 297 (void*) android_view_GraphiceBuffer_write }, 298 { "nReadGraphicBufferFromParcel", "(Landroid/os/Parcel;)I", 299 (void*) android_view_GraphiceBuffer_read }, 300 301 { "nLockCanvas", "(ILandroid/graphics/Canvas;Landroid/graphics/Rect;)Z", 302 (void*) android_view_GraphicBuffer_lockCanvas }, 303 { "nUnlockCanvasAndPost", "(ILandroid/graphics/Canvas;)Z", 304 (void*) android_view_GraphicBuffer_unlockCanvasAndPost }, 305 }; 306 307 int register_android_view_GraphicBuffer(JNIEnv* env) { 308 jclass clazz; 309 FIND_CLASS(clazz, "android/view/GraphicBuffer"); 310 GET_FIELD_ID(gGraphicBufferClassInfo.mNativeObject, clazz, "mNativeObject", "I"); 311 312 FIND_CLASS(clazz, "android/graphics/Rect"); 313 GET_METHOD_ID(gRectClassInfo.set, clazz, "set", "(IIII)V"); 314 GET_FIELD_ID(gRectClassInfo.left, clazz, "left", "I"); 315 GET_FIELD_ID(gRectClassInfo.top, clazz, "top", "I"); 316 GET_FIELD_ID(gRectClassInfo.right, clazz, "right", "I"); 317 GET_FIELD_ID(gRectClassInfo.bottom, clazz, "bottom", "I"); 318 319 FIND_CLASS(clazz, "android/graphics/Canvas"); 320 GET_FIELD_ID(gCanvasClassInfo.mFinalizer, clazz, "mFinalizer", 321 "Landroid/graphics/Canvas$CanvasFinalizer;"); 322 GET_FIELD_ID(gCanvasClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "I"); 323 GET_FIELD_ID(gCanvasClassInfo.mSurfaceFormat, clazz, "mSurfaceFormat", "I"); 324 325 FIND_CLASS(clazz, "android/graphics/Canvas$CanvasFinalizer"); 326 GET_FIELD_ID(gCanvasFinalizerClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "I"); 327 328 return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)); 329 } 330 331 }; 332