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