Home | History | Annotate | Download | only in graphics
      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 <nativehelper/JNIHelp.h>
     21 #include <inttypes.h>
     22 
     23 #include "android_os_Parcel.h"
     24 #include "GraphicBuffer.h"
     25 #include "GraphicsJNI.h"
     26 
     27 #include <android_runtime/AndroidRuntime.h>
     28 
     29 #include <binder/Parcel.h>
     30 
     31 #include <log/log.h>
     32 
     33 #include <ui/GraphicBuffer.h>
     34 #include <ui/PixelFormat.h>
     35 
     36 #include <hwui/Bitmap.h>
     37 
     38 #include <SkCanvas.h>
     39 #include <SkBitmap.h>
     40 
     41 #include <private/gui/ComposerService.h>
     42 
     43 #include "core_jni_helpers.h"
     44 
     45 namespace android {
     46 
     47 // ----------------------------------------------------------------------------
     48 // Defines
     49 // ----------------------------------------------------------------------------
     50 
     51 // Debug
     52 static const bool kDebugGraphicBuffer = false;
     53 
     54 #define LOCK_CANVAS_USAGE (GraphicBuffer::USAGE_SW_READ_OFTEN | GraphicBuffer::USAGE_SW_WRITE_OFTEN)
     55 
     56 // ----------------------------------------------------------------------------
     57 // JNI Helpers
     58 // ----------------------------------------------------------------------------
     59 
     60 static struct {
     61     jfieldID mNativeObject;
     62     jclass mClass;
     63     jmethodID mConstructorMethodID;
     64 } gGraphicBufferClassInfo;
     65 
     66 static struct {
     67     jmethodID set;
     68     jfieldID left;
     69     jfieldID top;
     70     jfieldID right;
     71     jfieldID bottom;
     72 } gRectClassInfo;
     73 
     74 #define GET_INT(object, field) \
     75     env->GetIntField(object, field)
     76 
     77 #define SET_INT(object, field, value) \
     78     env->SetIntField(object, field, value)
     79 
     80 #define GET_LONG(object, field) \
     81     env->GetLongField(object, field)
     82 
     83 #define SET_LONG(object, field, value) \
     84     env->SetLongField(object, field, value)
     85 
     86 #define INVOKEV(object, method, ...) \
     87     env->CallVoidMethod(object, method, __VA_ARGS__)
     88 
     89 // ----------------------------------------------------------------------------
     90 // Types
     91 // ----------------------------------------------------------------------------
     92 
     93 class GraphicBufferWrapper {
     94 public:
     95     explicit GraphicBufferWrapper(const sp<GraphicBuffer>& buffer): buffer(buffer) {
     96         LOG_ALWAYS_FATAL_IF(buffer == nullptr, "creating a null GraphicBuffer");
     97     }
     98     const sp<GraphicBuffer>& get() const {
     99         return buffer;
    100     }
    101 
    102 private:
    103     // make sure this is immutable
    104     sp<GraphicBuffer> const buffer;
    105 };
    106 
    107 // ----------------------------------------------------------------------------
    108 // GraphicBuffer lifecycle
    109 // ----------------------------------------------------------------------------
    110 
    111 static jlong android_graphics_GraphicBuffer_wrap(JNIEnv* env, jobject clazz,
    112         jlong unwrapped) {
    113     sp<GraphicBuffer> b(reinterpret_cast<GraphicBuffer*>(unwrapped));
    114     LOG_ALWAYS_FATAL_IF(b == nullptr,
    115             "*** android_graphics_GraphicBuffer_wrap() invalid state, b is null, unwrapped=%#" PRIx64, unwrapped);
    116     GraphicBufferWrapper* wrapper = new GraphicBufferWrapper(b);
    117     return reinterpret_cast<jlong>(wrapper);
    118 }
    119 
    120 static jlong android_graphics_GraphicBuffer_create(JNIEnv* env, jobject clazz,
    121         jint width, jint height, jint format, jint usage) {
    122 
    123     sp<GraphicBuffer> buffer = new GraphicBuffer(
    124             uint32_t(width), uint32_t(height), PixelFormat(format), uint32_t(usage),
    125             std::string("android_graphics_GraphicBuffer_create pid [") +
    126                     std::to_string(getpid()) +"]");
    127 
    128     status_t error = buffer->initCheck();
    129     if (error < 0) {
    130         ALOGW_IF(kDebugGraphicBuffer, "createGraphicBuffer() failed in GraphicBuffer.create()");
    131         return NULL;
    132     }
    133 
    134     GraphicBufferWrapper* wrapper = new GraphicBufferWrapper(buffer);
    135     return reinterpret_cast<jlong>(wrapper);
    136 }
    137 
    138 static void android_graphics_GraphicBuffer_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 
    149 static inline SkColorType convertPixelFormat(int32_t format) {
    150     switch (format) {
    151         case PIXEL_FORMAT_RGBA_8888:
    152             return kN32_SkColorType;
    153         case PIXEL_FORMAT_RGBX_8888:
    154             return kN32_SkColorType;
    155         case PIXEL_FORMAT_RGBA_FP16:
    156             return kRGBA_F16_SkColorType;
    157         case PIXEL_FORMAT_RGB_565:
    158             return kRGB_565_SkColorType;
    159         default:
    160             return kUnknown_SkColorType;
    161     }
    162 }
    163 
    164 static jboolean android_graphics_GraphicBuffer_lockCanvas(JNIEnv* env, jobject,
    165         jlong wrapperHandle, jobject canvas, jobject dirtyRect) {
    166 
    167     GraphicBufferWrapper* wrapper =
    168                 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
    169     if (!wrapper) {
    170         return JNI_FALSE;
    171     }
    172 
    173     sp<GraphicBuffer> buffer(wrapper->get());
    174 
    175     Rect rect(Rect::EMPTY_RECT);
    176     if (dirtyRect) {
    177         rect.left = GET_INT(dirtyRect, gRectClassInfo.left);
    178         rect.top = GET_INT(dirtyRect, gRectClassInfo.top);
    179         rect.right = GET_INT(dirtyRect, gRectClassInfo.right);
    180         rect.bottom = GET_INT(dirtyRect, gRectClassInfo.bottom);
    181     } else {
    182         rect.set(Rect(buffer->getWidth(), buffer->getHeight()));
    183     }
    184 
    185     void* bits = NULL;
    186     status_t status = buffer->lock(LOCK_CANVAS_USAGE, rect, &bits);
    187 
    188     if (status) return JNI_FALSE;
    189     if (!bits) {
    190         buffer->unlock();
    191         return JNI_FALSE;
    192     }
    193 
    194     ssize_t bytesCount = buffer->getStride() * bytesPerPixel(buffer->getPixelFormat());
    195 
    196     SkBitmap bitmap;
    197     bitmap.setInfo(SkImageInfo::Make(buffer->getWidth(), buffer->getHeight(),
    198                                      convertPixelFormat(buffer->getPixelFormat()),
    199                                      kPremul_SkAlphaType,
    200                                      GraphicsJNI::defaultColorSpace()),
    201                    bytesCount);
    202 
    203     if (buffer->getWidth() > 0 && buffer->getHeight() > 0) {
    204         bitmap.setPixels(bits);
    205     } else {
    206         bitmap.setPixels(NULL);
    207     }
    208 
    209     Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas);
    210     nativeCanvas->setBitmap(bitmap);
    211     nativeCanvas->clipRect(rect.left, rect.top, rect.right, rect.bottom,
    212             SkClipOp::kIntersect);
    213 
    214     if (dirtyRect) {
    215         INVOKEV(dirtyRect, gRectClassInfo.set,
    216                 int(rect.left), int(rect.top), int(rect.right), int(rect.bottom));
    217     }
    218 
    219     return JNI_TRUE;
    220 }
    221 
    222 static jboolean android_graphics_GraphicBuffer_unlockCanvasAndPost(JNIEnv* env, jobject,
    223         jlong wrapperHandle, jobject canvas) {
    224 
    225     GraphicBufferWrapper* wrapper =
    226                 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
    227     Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas);
    228     nativeCanvas->setBitmap(SkBitmap());
    229 
    230     if (wrapper) {
    231         status_t status = wrapper->get()->unlock();
    232         return status == 0 ? JNI_TRUE : JNI_FALSE;
    233     }
    234 
    235     return JNI_FALSE;
    236 }
    237 
    238 // ----------------------------------------------------------------------------
    239 // Serialization
    240 // ----------------------------------------------------------------------------
    241 
    242 static void android_graphics_GraphicBuffer_write(JNIEnv* env, jobject clazz,
    243         jlong wrapperHandle, jobject dest) {
    244 
    245     GraphicBufferWrapper* wrapper =
    246                 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
    247     Parcel* parcel = parcelForJavaObject(env, dest);
    248     if (parcel) {
    249         parcel->write(*wrapper->get());
    250     }
    251 }
    252 
    253 static jlong android_graphics_GraphicBuffer_read(JNIEnv* env, jobject clazz,
    254         jobject in) {
    255 
    256     Parcel* parcel = parcelForJavaObject(env, in);
    257     if (parcel) {
    258         sp<GraphicBuffer> buffer = new GraphicBuffer();
    259         parcel->read(*buffer);
    260         return reinterpret_cast<jlong>(new GraphicBufferWrapper(buffer));
    261     }
    262 
    263     return NULL;
    264 }
    265 
    266 // ----------------------------------------------------------------------------
    267 // External helpers
    268 // ----------------------------------------------------------------------------
    269 
    270 sp<GraphicBuffer> graphicBufferForJavaObject(JNIEnv* env, jobject obj) {
    271     if (obj) {
    272         jlong nativeObject = env->GetLongField(obj, gGraphicBufferClassInfo.mNativeObject);
    273         GraphicBufferWrapper* wrapper = (GraphicBufferWrapper*) nativeObject;
    274         if (wrapper != NULL) {
    275             sp<GraphicBuffer> buffer(wrapper->get());
    276             return buffer;
    277         }
    278     }
    279     return NULL;
    280 }
    281 
    282 jobject createJavaGraphicBuffer(JNIEnv* env, const sp<GraphicBuffer>& buffer) {
    283     GraphicBufferWrapper* wrapper = new GraphicBufferWrapper(buffer);
    284     jobject obj = env->NewObject(gGraphicBufferClassInfo.mClass,
    285             gGraphicBufferClassInfo.mConstructorMethodID, buffer->getWidth(), buffer->getHeight(),
    286             buffer->getPixelFormat(), (jint)buffer->getUsage(), reinterpret_cast<jlong>(wrapper));
    287     return obj;
    288 }
    289 
    290 };
    291 
    292 using namespace android;
    293 // ----------------------------------------------------------------------------
    294 // JNI Glue
    295 // ----------------------------------------------------------------------------
    296 
    297 const char* const kClassPathName = "android/graphics/GraphicBuffer";
    298 
    299 static const JNINativeMethod gMethods[] = {
    300     { "nCreateGraphicBuffer",  "(IIII)J", (void*) android_graphics_GraphicBuffer_create },
    301     { "nDestroyGraphicBuffer", "(J)V",    (void*) android_graphics_GraphicBuffer_destroy },
    302 
    303     { "nWriteGraphicBufferToParcel",  "(JLandroid/os/Parcel;)V",
    304             (void*) android_graphics_GraphicBuffer_write },
    305     { "nReadGraphicBufferFromParcel", "(Landroid/os/Parcel;)J",
    306             (void*) android_graphics_GraphicBuffer_read },
    307 
    308     { "nLockCanvas", "(JLandroid/graphics/Canvas;Landroid/graphics/Rect;)Z",
    309             (void*) android_graphics_GraphicBuffer_lockCanvas },
    310     { "nUnlockCanvasAndPost", "(JLandroid/graphics/Canvas;)Z",
    311             (void*) android_graphics_GraphicBuffer_unlockCanvasAndPost },
    312     { "nWrapGraphicBuffer", "(J)J",
    313             (void*) android_graphics_GraphicBuffer_wrap }
    314 };
    315 
    316 int register_android_graphics_GraphicBuffer(JNIEnv* env) {
    317     gGraphicBufferClassInfo.mClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, kClassPathName));
    318     gGraphicBufferClassInfo.mNativeObject = GetFieldIDOrDie(env, gGraphicBufferClassInfo.mClass,
    319             "mNativeObject", "J");
    320     gGraphicBufferClassInfo.mConstructorMethodID = env->GetMethodID(gGraphicBufferClassInfo.mClass,
    321             "<init>", "(IIIIJ)V");
    322 
    323     jclass clazz = FindClassOrDie(env, "android/graphics/Rect");
    324     gRectClassInfo.set = GetMethodIDOrDie(env, clazz, "set", "(IIII)V");
    325     gRectClassInfo.left = GetFieldIDOrDie(env, clazz, "left", "I");
    326     gRectClassInfo.top = GetFieldIDOrDie(env, clazz, "top", "I");
    327     gRectClassInfo.right = GetFieldIDOrDie(env, clazz, "right", "I");
    328     gRectClassInfo.bottom = GetFieldIDOrDie(env, clazz, "bottom", "I");
    329 
    330     return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
    331 }
    332