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