android_view_GraphicBuffer.cpp revision 18b4cbeedef21c1fa666a110a157bab66edff976
1326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams/* 2326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams * Copyright (C) 2013 The Android Open Source Project 3326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams * 4326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams * Licensed under the Apache License, Version 2.0 (the "License"); 5326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams * you may not use this file except in compliance with the License. 6326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams * You may obtain a copy of the License at 7326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams * 8326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams * http://www.apache.org/licenses/LICENSE-2.0 9326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams * 10326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams * Unless required by applicable law or agreed to in writing, software 11326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams * distributed under the License is distributed on an "AS IS" BASIS, 12326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams * See the License for the specific language governing permissions and 14326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams * limitations under the License. 15326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams */ 16326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams 17326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#define LOG_TAG "GraphicBuffer" 18326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams 19326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#include "jni.h" 20326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#include "JNIHelp.h" 21326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams 22326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#include "android_os_Parcel.h" 23326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#include "android_view_GraphicBuffer.h" 24326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams 25326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#include <android_runtime/AndroidRuntime.h> 26326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams 27326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#include <binder/Parcel.h> 28326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams 29326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#include <ui/GraphicBuffer.h> 30326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#include <ui/PixelFormat.h> 31326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams 32326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#include <gui/IGraphicBufferAlloc.h> 33326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#include <gui/ISurfaceComposer.h> 34326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams 35326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#include <SkCanvas.h> 36a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams#include <SkBitmap.h> 37a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams 38a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams#include <private/gui/ComposerService.h> 39a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams 40a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Samsnamespace android { 41326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams 42a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams// ---------------------------------------------------------------------------- 43326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams// Defines 44326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams// ---------------------------------------------------------------------------- 45326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams 46326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams// Debug 47326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#define DEBUG_GRAPHIC_BUFFER 0 48326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams 49326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams// Debug 50326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#if DEBUG_GRAPHIC_BUFFER 51326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams #define GB_LOGD(...) ALOGD(__VA_ARGS__) 52326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams #define GB_LOGW(...) ALOGW(__VA_ARGS__) 53326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#else 54326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams #define GB_LOGD(...) 55326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams #define GB_LOGW(...) 561030893d9b99b72468034da13df025bda479bb97Jason Sams#endif 571030893d9b99b72468034da13df025bda479bb97Jason Sams 58a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams#define LOCK_CANVAS_USAGE GraphicBuffer::USAGE_SW_READ_OFTEN | GraphicBuffer::USAGE_SW_WRITE_OFTEN 59a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams 60a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams// ---------------------------------------------------------------------------- 611030893d9b99b72468034da13df025bda479bb97Jason Sams// JNI Helpers 621030893d9b99b72468034da13df025bda479bb97Jason Sams// ---------------------------------------------------------------------------- 631030893d9b99b72468034da13df025bda479bb97Jason Sams 641030893d9b99b72468034da13df025bda479bb97Jason Samsstatic struct { 65a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams jfieldID mNativeObject; 66a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams} gGraphicBufferClassInfo; 67a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams 681030893d9b99b72468034da13df025bda479bb97Jason Samsstatic struct { 691030893d9b99b72468034da13df025bda479bb97Jason Sams jmethodID set; 70326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams jfieldID left; 71326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams jfieldID top; 72326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams jfieldID right; 73326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams jfieldID bottom; 74326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams} gRectClassInfo; 75326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams 76326e0ddf89e8df2837752fbfd7a014814b32082cJason Samsstatic struct { 77326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams jfieldID mFinalizer; 78a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams jfieldID mNativeCanvas; 79a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams jfieldID mSurfaceFormat; 80a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams} gCanvasClassInfo; 81326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams 82326e0ddf89e8df2837752fbfd7a014814b32082cJason Samsstatic struct { 83326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams jfieldID mNativeCanvas; 84a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams} gCanvasFinalizerClassInfo; 85a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams 86a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams#define GET_INT(object, field) \ 87a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams env->GetIntField(object, field) 88326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams 89326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#define SET_INT(object, field, value) \ 90326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams env->SetIntField(object, field, value) 91326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams 92326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#define GET_LONG(object, field) \ 93326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams env->GetLongField(object, field) 94326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams 95326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#define SET_LONG(object, field, value) \ 96326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams env->SetLongField(object, field, value) 97326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams 98326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#define INVOKEV(object, method, ...) \ 99326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams env->CallVoidMethod(object, method, __VA_ARGS__) 100326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams 101326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams// ---------------------------------------------------------------------------- 102326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams// Types 103326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams// ---------------------------------------------------------------------------- 104326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams 105326e0ddf89e8df2837752fbfd7a014814b32082cJason Samsclass GraphicBufferWrapper { 106326e0ddf89e8df2837752fbfd7a014814b32082cJason Samspublic: 107326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams GraphicBufferWrapper(const sp<GraphicBuffer>& buffer): buffer(buffer) { 108326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams } 109326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams 110326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams sp<GraphicBuffer> buffer; 111326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams}; 112326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams 113326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams// ---------------------------------------------------------------------------- 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