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