android_view_GraphicBuffer.cpp revision 7023df08f14ec5dee76ac54c03e870f84e297636
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 INVOKEV(object, method, ...) \ 93 env->CallVoidMethod(object, method, __VA_ARGS__) 94 95// ---------------------------------------------------------------------------- 96// Types 97// ---------------------------------------------------------------------------- 98 99class GraphicBufferWrapper { 100public: 101 GraphicBufferWrapper(const sp<GraphicBuffer>& buffer): buffer(buffer) { 102 } 103 104 sp<GraphicBuffer> buffer; 105}; 106 107// ---------------------------------------------------------------------------- 108// GraphicBuffer lifecycle 109// ---------------------------------------------------------------------------- 110 111static 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 131static void android_view_GraphiceBuffer_destroy(JNIEnv* env, jobject clazz, 132 GraphicBufferWrapper* wrapper) { 133 delete wrapper; 134} 135 136// ---------------------------------------------------------------------------- 137// Canvas management 138// ---------------------------------------------------------------------------- 139 140static 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 149static 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 162static 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 219static 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 237static 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 245static 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 262sp<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 290const char* const kClassPathName = "android/view/GraphicBuffer"; 291 292static 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 307int 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